--- /dev/null
+---
+BasedOnStyle: Mozilla
+---
+Language: Cpp
+AllowAllParametersOfDeclarationOnNextLine: true
+PointerAlignment: Right
+SpaceBeforeParens: Always
+ColumnLimit: 100
+IndentWidth: 4
+AlignEscapedNewlines: DontAlign
+...
--- /dev/null
+
+
+# In addition to regular commit message, you can uncomment and fill in the
+# following to include this change in the released RPM package changelog:
+
+# = changelog =
+# msg:
+# type:
+# resolves:
+# related:
+
+# msg = message to be included in the changelog
+# type = one of: bugfix/enhancement/security
+# resolves = URLs to bugs or issues resolved by this commit
+# related = URLs to any related bugs or issues
+
--- /dev/null
+---
+name: DNF CI
+on: pull_request_target
+
+jobs:
+ copr-build:
+ name: Copr Build
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/rpm-software-management/dnf-ci-host
+ outputs:
+ package-urls: ${{steps.copr-build.outputs.package-urls}}
+ steps:
+ - name: Check out ci-dnf-stack
+ uses: actions/checkout@v2
+ with:
+ repository: rpm-software-management/ci-dnf-stack
+ ref: dnf-4-stack
+
+
+ - name: Setup CI
+ id: setup-ci
+ uses: ./.github/actions/setup-ci
+ with:
+ copr-user: ${{secrets.COPR_USER}}
+ copr-api-token: ${{secrets.COPR_API_TOKEN}}
+
+ - name: Check out sources
+ uses: actions/checkout@v2
+ with:
+ path: gits/${{github.event.repository.name}}
+ ref: ${{github.event.pull_request.head.sha}} # check out the PR HEAD
+ fetch-depth: 0
+
+ - name: Run Copr Build
+ id: copr-build
+ uses: ./.github/actions/copr-build
+ with:
+ copr-user: ${{steps.setup-ci.outputs.copr-user}}
+
+ integration-tests:
+ name: DNF Integration Tests
+ needs: copr-build
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/rpm-software-management/dnf-ci-host
+ options: --privileged
+ volumes:
+ # A workaround for an undeterministic "OCI not found" error, see
+ # https://github.com/containers/podman/issues/10321
+ - /var/lib/mycontainer:/var/lib/containers
+ steps:
+ - name: Check out ci-dnf-stack
+ uses: actions/checkout@v2
+ with:
+ repository: rpm-software-management/ci-dnf-stack
+ ref: dnf-4-stack
+
+ - name: Run Integration Tests
+ uses: ./.github/actions/integration-tests
+ with:
+ package-urls: ${{needs.copr-build.outputs.package-urls}}
+
+ ansible-tests:
+ name: Ansible Tests
+ needs: copr-build
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/rpm-software-management/dnf-ci-host
+ options: --privileged
+ steps:
+ - name: Check out ci-dnf-stack
+ uses: actions/checkout@v2
+ with:
+ repository: rpm-software-management/ci-dnf-stack
+ ref: dnf-4-stack
+
+ - name: Run Ansible Tests
+ uses: ./.github/actions/ansible-tests
+ with:
+ package-urls: ${{needs.copr-build.outputs.package-urls}}
--- /dev/null
+# These are currently the only two things that
+# show up in a srcdir != builddir build.
+/docs/libdnf/version.xml
+/libdnf/dnf-version.h
+build
+*.pyc
+data/tests/modules/yum.repos.d/test.repo
+libdnf/config-64.h
--- /dev/null
+# See the documentation for more information:
+# https://packit.dev/docs/configuration/
+
+specfile_path: libdnf.spec
+
+jobs:
+ - job: copr_build
+ trigger: pull_request
+ targets:
+ - fedora-all
+ - job: tests
+ trigger: pull_request
+ identifier: "dnf-tests"
+ targets:
+ - fedora-all
+ fmf_url: https://github.com/rpm-software-management/ci-dnf-stack.git
+ fmf_ref: enable-tmt-dnf-4-stack
+ tmt_plan: "^/plans/integration/behave-dnf$"
+
--- /dev/null
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+- repo: https://github.com/rpm-software-management/rpmlint.git
+ rev: 2.5.0
+ hooks:
+ - id: rpmlint
+ files: ^libdnf\.spec$
+ # Passes if packit not installed. Needed for validation locally
+- repo: https://github.com/packit/pre-commit-hooks
+ rev: v1.2.0
+ hooks:
+ - id: validate-config
--- /dev/null
+the .tito/packages directory contains metadata files
+named after their packages. Each file has the latest tagged
+version and the project's relative directory.
--- /dev/null
+[buildconfig]
+builder = tito.builder.Builder
+tagger = tito.tagger.VersionTagger
+changelog_do_not_remove_cherrypick = 0
+changelog_format = %s (%ae)
--- /dev/null
+Richard Hughes <richard@hughsie.com>
+Igor Gnatenko <ignatenko@redhat.com>
+Jaroslav Mracek <jmracek@redhat.com>
+Jaroslav Rohel <jrohel@redhat.com>
+Daniel Mach <dmach@redhat.com>
+Marek Blaha <mblaha@redhat.com>
+Pavla Kratochvilova <pkratoch@redhat.com>
+Michal Domonkos <mdomonko@redhat.com>
+Ales Matej <amatej@redhat.com>
+
+-------------------
+Libdnf CONTRIBUTORS
+-------------------
+Zhang Xianwei <zhang.xianwei8@zte.com.cn>
+Bernhard Rosenkraenzer <bero@lindev.ch>
+Dmitry Antipov <dantipov@cloudlinux.com>
+
+--------------
+Hawkey AUTHORS
+--------------
+ Ales Kozumplik <ales@redhat.com>
+ Jan Silhan <jsilhan@redhat.com>
+ Michal Luscon <mluscon@redhat.com>
+ Michael Mraka <michael.mraka@redhat.com>
+ Radek Holy <rholy@redhat.com>
+ Zdenek Pavlas <zpavlas@redhat.com>
+
+-------------------
+Hawkey CONTRIBUTORS
+-------------------
+ Colin Walters <walters@verbum.org>
+ Matthew Barnes <mbarnes@redhat.com>
+ Michal Ruprich <michalruprich@gmail.com>
+ Peter Hjalmarsson <kanelxake@gmail.com>
+ Richard Hughes <richard@hughsie.com>
+ Scott Tsai <scottt.tw@gmail.com>
+ Tomas Mlcoch <tmlcoch@redhat.com>
--- /dev/null
+# print initial information about the project
+message("Running CMake on libdnf...")
+project(libdnf C CXX)
+
+
+# cmake requirements and policies
+cmake_minimum_required(VERSION 2.8.5)
+cmake_policy(SET CMP0005 OLD)
+# Avoid a warning because "hth" links to
+# the in-tree libhawkey, but uses pkg-config to find
+# GLib. There may be a better way to do this...
+cmake_policy(SET CMP0003 NEW)
+include(GNUInstallDirs)
+
+
+# use project specific cmake modules
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
+if(${CMAKE_VERSION} VERSION_LESS 3)
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${CMAKE_SOURCE_DIR}/cmake/modules-cmake-2)
+endif()
+
+
+# print exact name and version of the compiled project
+include(VERSION.cmake)
+message("Building ${PROJECT_NAME} version: ${LIBDNF_VERSION}")
+
+
+# build options
+option(WITH_BINDINGS "Enables python/SWIG bindings" ON)
+option(ENABLE_STATIC "Build a static library instead of shared" OFF)
+option(WITH_GTKDOC "Enables libdnf GTK-Doc HTML documentation" ON)
+option(WITH_HTML "Enables hawkey HTML generation" ON)
+option(WITH_MAN "Enables hawkey man page generation" ON)
+option(WITH_ZCHUNK "Build with zchunk support" ON)
+option(ENABLE_RHSM_SUPPORT "Build with Red Hat Subscription Manager support?" OFF)
+option(ENABLE_SOLV_URPMREORDER "Build with support for URPM-like solution reordering?" OFF)
+option(WITH_TESTS "Enables unit tests" ON)
+
+
+# build options - debugging
+option(WITH_SANITIZERS "Build with address, leak and undefined sanitizers (DEBUG ONLY)" OFF)
+
+
+# load pkg-config first; it's required by other modules
+find_package(PkgConfig REQUIRED)
+if(APPLE)
+ set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib64/pkgconfig")
+ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};/usr/local/share/cmake/Modules/)
+ include_directories(/usr/local/include)
+endif()
+
+
+# build dependencies
+find_package(LibSolv 0.7.21 REQUIRED COMPONENTS ext)
+
+
+# build dependencies via pkg-config
+pkg_check_modules(CHECK REQUIRED check)
+pkg_check_modules(GLIB REQUIRED gio-unix-2.0>=2.46.0)
+include_directories(${GLIB_INCLUDE_DIRS})
+pkg_check_modules(JSONC REQUIRED json-c)
+include_directories(${JSONC_INCLUDE_DIRS})
+pkg_check_modules(LIBMODULEMD REQUIRED modulemd-2.0>=2.11.2)
+pkg_check_modules(REPO REQUIRED librepo>=1.15.0)
+include_directories(${REPO_INCLUDE_DIRS})
+link_directories(${REPO_LIBRARY_DIRS})
+pkg_check_modules(RPM REQUIRED rpm>=4.15.0)
+pkg_check_modules(SMARTCOLS REQUIRED smartcols)
+pkg_check_modules(SQLite3 REQUIRED sqlite3)
+
+# always enable linking with libdnf utils
+include_directories(${CMAKE_SOURCE_DIR} libdnf/utils/)
+
+if (WITH_ZCHUNK)
+ pkg_check_modules(ZCHUNKLIB zck>=0.9.11 REQUIRED)
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWITH_ZCHUNK")
+ set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DWITH_ZCHUNK")
+endif ()
+
+if(ENABLE_RHSM_SUPPORT)
+ pkg_check_modules(RHSM REQUIRED librhsm>=0.0.3)
+ include_directories(${RHSM_INCLUDE_DIRS})
+endif()
+
+
+# glibc: check if fnmatch.h has FNM_CASEFOLD symbol
+include(CheckSymbolExists)
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+check_symbol_exists(FNM_CASEFOLD "fnmatch.h" HAS_FNM_CASEFOLD)
+if(NOT HAS_FNM_CASEFOLD)
+ message(SEND_ERROR "FNM_CASEFOLD is not available in fnmatch.h")
+endif()
+
+# python
+if(WITH_BINDINGS)
+ if(NOT PYTHON_DESIRED)
+ find_package(PythonInterp REQUIRED)
+ elseif(${PYTHON_DESIRED} STREQUAL "2")
+ find_package(PythonInterp 2 EXACT REQUIRED)
+ elseif(${PYTHON_DESIRED} STREQUAL "3")
+ find_package(PythonInterp 3 EXACT REQUIRED)
+ elseif(EXISTS ${PYTHON_DESIRED})
+ set(PYTHON_EXECUTABLE ${PYTHON_DESIRED})
+ find_package(PythonInterp REQUIRED)
+ else()
+ message(FATAL_ERROR "Invalid PYTHON_DESIRED value: " ${PYTHON_DESIRED})
+ endif()
+ find_package(PythonLibs REQUIRED)
+ message(STATUS "Building for python${PYTHON_VERSION_MAJOR}")
+else()
+ message(STATUS "Not building language bindings")
+endif()
+
+
+# compiler options
+add_compile_options(-Wcast-align -Wno-uninitialized -Wredundant-decls -Wwrite-strings -Wformat-nonliteral -Wmissing-format-attribute -Wsign-compare -Wtype-limits -Wuninitialized -Wall -Wl,--as-needed)
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -Wmissing-prototypes -Waggregate-return -Wshadow -Werror=implicit-function-declaration")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wmissing-declarations")
+
+# apple: turn rpath off
+set(CMAKE_MACOSX_RPATH 0)
+
+# package/project version
+add_definitions(-DPACKAGE_VERSION=\\"${LIBDNF_VERSION}\\")
+
+# The libdnf API is under development now. This enables it for internal usage.
+add_definitions(-DLIBDNF_UNSTABLE_API)
+
+# gettext
+add_definitions(-DGETTEXT_DOMAIN=\\"libdnf\\")
+add_definitions(-DG_LOG_DOMAIN=\\"libdnf\\")
+
+# tests
+add_definitions(-DTESTDATADIR=\\"${CMAKE_SOURCE_DIR}/data/tests\\")
+
+# librhsm
+if(ENABLE_RHSM_SUPPORT)
+ add_definitions(-DRHSM_SUPPORT)
+endif()
+
+# libsolv
+if(ENABLE_SOLV_URPMREORDER)
+ add_definitions(-DLIBSOLV_FLAG_URPMREORDER=1)
+endif()
+
+# If defined, libsolv adds the prefix "dep_" to solvable dependencies.
+# As a result, `requires` is renamed to `dep_requires`.
+# Needed for C++20. `requires` is a keyword in C++20.
+add_definitions(-DLIBSOLV_SOLVABLE_PREPEND_DEP)
+
+if(WITH_SANITIZERS)
+ message(WARNING "Building with sanitizers enabled!")
+ add_compile_options(-fsanitize=address -fsanitize=undefined -fsanitize=leak)
+ link_libraries(asan ubsan)
+endif()
+
+
+# build binaries
+add_subdirectory(libdnf)
+if(WITH_BINDINGS)
+ # add_subdirectory(bindings/perl)
+ add_subdirectory(bindings/python)
+endif()
+
+
+# build translations
+add_subdirectory(po)
+
+
+# build docs
+add_subdirectory(docs/libdnf)
+if(WITH_BINDINGS)
+ add_subdirectory(docs/hawkey)
+endif()
+
+
+# build tests
+IF (WITH_TESTS)
+enable_testing()
+add_subdirectory(tests)
+ENDIF()
+if(WITH_BINDINGS)
+ add_subdirectory(python/hawkey)
+endif()
+
+
+add_subdirectory(etc)
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+libdnf
+======
+
+This library provides a high level package-manager. It's core library of [dnf](https://github.com/rpm-software-management/dnf), [PackageKit](https://github.com/hughsie/PackageKit) and [rpm-ostree](https://github.com/projectatomic/rpm-ostree). It's replacement for deprecated [hawkey library](https://github.com/rpm-software-management/hawkey) which it contains inside and uses [librepo](https://github.com/rpm-software-management/librepo) under the hood.
+
+:warning: :warning: :warning:
+**Note that libdnf is currently being reworked and is
+considered unstable. Once major users like PackageKit and
+DNF are fully ported, a new stable release will be
+considered.**
+:warning: :warning: :warning:
+
+License
+----
+
+LGPLv2+
+
+Building for Fedora
+===================
+
+To install build requirements, run following command:
+
+ dnf install check-devel cmake cppunit-devel gcc gcc-c++ glib2-devel gtk-doc json-c-devel libmodulemd-devel librepo-devel libsolv-devel libsolv-tools make python2-devel python3-devel python2-sphinx python3-sphinx python2-breathe python3-breathe rpm-devel sqlite-devel swig libsmartcols-devel
+
+From the checkout dir:
+
+ mkdir build
+ cd build/
+ cmake .. -DPYTHON_DESIRED=3
+ make
+
+Building the documentation, from the build/ directory::
+
+ make doc
+
+Building RPMs:
+
+ tito build --rpm --test
+
+Tests
+=====
+
+All unit tests should pass after the build finishes:
+
+ cd build
+ make test
+
+There are two parts of unit tests: unit tests in C and unit tests in Python. To run the C part of the tests manually, from hawkey checkout::
+
+ build/tests/test_main tests/repos/
+
+To manually execute the Python tests, from libdnf git checkout directory::
+
+ PYTHONPATH=`readlink -f ./build/src/python/` python3 -m unittest discover -bt python/hawkey/tests/ -s python/hawkey/tests/tests/
+
+The PYTHONPATH is unfortunately needed as the Python test suite needs to know where to import the built hawkey modules.
+
+Contribution
+============
+
+Here's the most direct way to get your work merged into the project.
+
+1. Fork the project
+1. Clone down your fork
+1. Implement your feature or bug fix and commit changes
+1. If the change fixes a bug at [Red Hat bugzilla](https://bugzilla.redhat.com/), or if it is important to the end user, add the following block to the commit message:
+
+ = changelog =
+ msg: message to be included in the changelog
+ type: one of: bugfix/enhancement/security (this field is required when message is present)
+ resolves: URLs to bugs or issues resolved by this commit (can be specified multiple times)
+ related: URLs to any related bugs or issues (can be specified multiple times)
+
+ * For example::
+
+ = changelog =
+ msg: Do not close the database if it wasn't opened
+ type: bugfix
+ resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1761976
+
+ * For your convenience, you can also use git commit template by running the following command in the top-level directory of this project:
+
+ git config commit.template ./.git-commit-template
+
+1. In a separate commit, add your name and email under ``Libdnf CONTRIBUTORS`` section in the [authors file](https://github.com/rpm-software-management/libdnf/blob/dnf-4-master/README.md) as a reward for your generosity
+1. Push the branch to your fork
+1. Send a pull request for your branch
+
+Please do not create pull requests with translation (.po) file improvements. Fix the translation on `Fedora Weblate <https://translate.fedoraproject.org/projects/dnf/>`_ instead.
+
+Documentation
+=============
+
+See the [hawkey documentation page](http://hawkey.readthedocs.org).
+
+Information internal to the hawkey development is maintained on a [github wiki](https://github.com/rpm-software-management/dnf/wiki#wiki-Contact).
+
+Useful links
+============
+
+Bug database:
+
+ * [libdnf github issues](https://github.com/rpm-software-management/libdnf/issues)
+ * [bugzilla](https://bugzilla.redhat.com/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=POST&bug_status=MODIFIED&bug_status=ON_DEV&bug_status=ON_QA&bug_status=VERIFIED&bug_status=RELEASE_PENDING&bug_status=CLOSED&component=libdnf&list_id=8513553&product=Fedora&query_format=advanced)
+
--- /dev/null
+set (DEFAULT_LIBDNF_MAJOR_VERSION 0)
+set (DEFAULT_LIBDNF_MINOR_VERSION 73)
+set (DEFAULT_LIBDNF_MICRO_VERSION 2)
+
+if(DEFINED LIBDNF_MAJOR_VERSION)
+ if(NOT ${DEFAULT_LIBDNF_MAJOR_VERSION} STREQUAL ${LIBDNF_MAJOR_VERSION})
+ message(FATAL_ERROR "Variable DEFAULT_LIBDNF_MAJOR_VERSION=" ${DEFAULT_LIBDNF_MAJOR_VERSION} " in VERSION.cmake differs from LIBDNF_MAJOR_VERSION=" ${LIBDNF_MAJOR_VERSION} " in spec")
+ endif()
+else()
+ set (LIBDNF_MAJOR_VERSION ${DEFAULT_LIBDNF_MAJOR_VERSION})
+endif()
+
+if(DEFINED LIBDNF_MINOR_VERSION)
+ if(NOT ${DEFAULT_LIBDNF_MINOR_VERSION} STREQUAL ${LIBDNF_MINOR_VERSION})
+ message(FATAL_ERROR "Variable DEFAULT_LIBDNF_MINOR_VERSION=" ${DEFAULT_LIBDNF_MINOR_VERSION} " in VERSION.cmake differs from LIBDNF_MINOR_VERSION=" ${LIBDNF_MINOR_VERSION} " in spec")
+ endif()
+else()
+ set (LIBDNF_MINOR_VERSION ${DEFAULT_LIBDNF_MINOR_VERSION})
+endif()
+
+if(DEFINED LIBDNF_MICRO_VERSION)
+ if(NOT ${DEFAULT_LIBDNF_MICRO_VERSION} STREQUAL ${LIBDNF_MICRO_VERSION})
+ message(FATAL_ERROR "Variable DEFAULT_LIBDNF_MICRO_VERSION=" ${DEFAULT_LIBDNF_MICRO_VERSION} " in VERSION.cmake differs from LIBDNF_MICRO_VERSION=" ${LIBDNF_MICRO_VERSION} " in spec")
+ endif()
+else()
+ set (LIBDNF_MICRO_VERSION ${DEFAULT_LIBDNF_MICRO_VERSION})
+endif()
+set (LIBDNF_VERSION ${LIBDNF_MAJOR_VERSION}.${LIBDNF_MINOR_VERSION}.${LIBDNF_MICRO_VERSION})
--- /dev/null
+find_package(SWIG REQUIRED)
+include(UseSWIG)
+
+
+message("Building for perl")
+find_package(Perl REQUIRED)
+find_package(PerlLibs REQUIRED)
+
+
+include_directories(${CMAKE_SOURCE_DIR})
+include_directories(${PERL_INCLUDE_PATH})
+include(UseSWIG)
+
+
+set_source_files_properties(../swig/utils.i PROPERTIES CPLUSPLUS ON)
+swig_add_module(utils perl ../swig/utils.i)
+swig_link_libraries(utils libdnf)
+swig_link_libraries(utils ${PERL_LIBRARY})
+swig_link_libraries(utils ${SQLite3_LIBRARIES})
+
+set_source_files_properties(../swig/transaction.i PROPERTIES CPLUSPLUS ON)
+swig_add_module(transaction perl ../swig/transaction.i)
+swig_link_libraries(transaction libdnf)
+swig_link_libraries(transaction ${PERL_LIBRARY})
--- /dev/null
+find_package(PythonInstDir)
+find_package(SWIG REQUIRED)
+include(UseSWIG)
+
+message(STATUS "Building for python${PYTHON_VERSION_MAJOR}")
+
+find_package(PythonInstDir)
+
+include_directories(${CMAKE_SOURCE_DIR})
+include_directories(${PYTHON_INCLUDE_PATH})
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ # using 64bit architecture
+ set(CMAKE_SWIG_FLAGS "-DSWIGWORDSIZE64")
+endif()
+
+# The libdnf API is under development now. This enables it for internal usage.
+set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} "-DLIBDNF_UNSTABLE_API")
+
+function(libdnf_swig_module name)
+ set(source ../swig/${name}.i)
+ set_source_files_properties(${source} PROPERTIES CPLUSPLUS ON)
+ swig_add_module(${name} python ${source})
+
+ foreach(lib ${ARGN})
+ swig_link_libraries(${name} ${lib})
+ endforeach()
+
+ install(TARGETS _${name} LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}/libdnf)
+ install(FILES ${CMAKE_BINARY_DIR}/bindings/python/${name}.py DESTINATION ${PYTHON_INSTALL_DIR}/libdnf)
+endfunction()
+
+libdnf_swig_module(error libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(common_types libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(conf libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(module libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(repo libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(smartcols libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(transaction libdnf ${PYTHON_LIBRARY})
+libdnf_swig_module(utils libdnf ${PYTHON_LIBRARY} ${SQLite3_LIBRARIES})
+
+configure_file(__init__.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py COPYONLY)
+install(FILES __init__.py DESTINATION ${PYTHON_INSTALL_DIR}/libdnf)
+
+set(DISTINFO_PATH "${CMAKE_CURRENT_BINARY_DIR}/libdnf-${LIBDNF_VERSION}.dist-info")
+set(METADATA_FILE "${DISTINFO_PATH}/METADATA")
+file(MAKE_DIRECTORY ${DISTINFO_PATH})
+file(WRITE ${METADATA_FILE} "Metadata-Version: 2.1\n")
+file(APPEND ${METADATA_FILE} "Name: libdnf\n")
+file(APPEND ${METADATA_FILE} "Version: ${LIBDNF_VERSION}\n")
+install(DIRECTORY ${DISTINFO_PATH} DESTINATION ${PYTHON_INSTALL_DIR})
--- /dev/null
+from __future__ import absolute_import
+
+# error needs to be imported first and with global visibility for its symbols,
+# as it defines a python exception, which is a global variable and the other
+# modules use the symbol.
+import sys, os
+sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
+from . import error
+
+# Other modules also need to be loaded with RTLD_GLOBAL to preserve uniqueness
+# of RTTI. There are code paths where an exception thrown in one module is
+# supposed to be caught in another.
+from . import common_types
+from . import conf
+from . import module
+from . import repo
+from . import transaction
+from . import utils
+sys.setdlopenflags(os.RTLD_NOW)
--- /dev/null
+// Beware of nested %includes / %imports. SWIG has a guard to %include each
+// file only once, but if you include this in a file that you later import into
+// another file, the exception handler will not work and a subsequent %include of
+// this file will not work either.
+
+%include <exception.i>
+
+%{
+ #include "libdnf/error.hpp"
+ extern PyObject* libdnf_error;
+%}
+
+%exception {
+ try {
+ $action
+ } catch (const libdnf::Error & e) {
+ PyErr_SetString(libdnf_error, const_cast<char*>(e.what()));
+ SWIG_fail;
+ } catch (const std::out_of_range & e) {
+ SWIG_exception(SWIG_IndexError, e.what());
+ } catch (const std::exception & e) {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
--- /dev/null
+%module common_types
+
+%begin %{
+ #define SWIG_PYTHON_2_UNICODE
+%}
+
+%include <exception.i>
+%include <stdint.i>
+%include <std_map.i>
+%include <std_pair.i>
+%include <std_set.i>
+%include <std_string.i>
+%include <std_vector.i>
+
+// Cant use %include <catch_error.i> here, SWIG includes each file only once,
+// but the exception handler actually doesnt get registered when this file is
+// %imported (as opposed to %included).
+%exception {
+ try {
+ $action
+ } catch (const std::out_of_range & e) {
+ SWIG_exception(SWIG_IndexError, e.what());
+ } catch (const std::exception & e) {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%template(SetString) std::set<std::string>;
+%template(PairStringString) std::pair<std::string, std::string>;
+%template(VectorPairStringString) std::vector<std::pair<std::string, std::string>>;
+%template(MapStringString) std::map<std::string, std::string>;
+%template(MapStringMapStringString) std::map<std::string, std::map<std::string, std::string>>;
+%template(MapStringPairStringString) std::map<std::string, std::pair<std::string, std::string>>;
+
+%{
+ #include "libdnf/utils/PreserveOrderMap.hpp"
+%}
+
+%ignore libdnf::PreserveOrderMap::MyBidirIterator;
+%ignore libdnf::PreserveOrderMap::MyBidirIterator::operator++;
+%ignore libdnf::PreserveOrderMap::MyBidirIterator::operator--;
+%ignore libdnf::PreserveOrderMap::begin;
+%ignore libdnf::PreserveOrderMap::end;
+%ignore libdnf::PreserveOrderMap::cbegin;
+%ignore libdnf::PreserveOrderMap::cend;
+%ignore libdnf::PreserveOrderMap::rbegin;
+%ignore libdnf::PreserveOrderMap::rend;
+%ignore libdnf::PreserveOrderMap::crbegin;
+%ignore libdnf::PreserveOrderMap::crend;
+%ignore libdnf::PreserveOrderMap::insert;
+%ignore libdnf::PreserveOrderMap::erase(const_iterator pos);
+%ignore libdnf::PreserveOrderMap::erase(const_iterator first, const_iterator last);
+%ignore libdnf::PreserveOrderMap::count;
+%ignore libdnf::PreserveOrderMap::find;
+%ignore libdnf::PreserveOrderMap::operator[];
+%ignore libdnf::PreserveOrderMap::at;
+%include "libdnf/utils/PreserveOrderMap.hpp"
+
+%inline %{
+class StopIterator {};
+
+template<class T>
+class Iterator {
+public:
+ Iterator(typename T::iterator _cur, typename T::iterator _end) : cur(_cur), end(_end) {}
+ Iterator* __iter__()
+ {
+ return this;
+ }
+
+ typename T::iterator cur;
+ typename T::iterator end;
+ };
+%}
+
+%define EXTEND_TEMPLATE_PreserveOrderMap(ReturnT, Key, T...)
+ %extend libdnf::PreserveOrderMap<Key, T> {
+ ReturnT __getitem__(const Key & key)
+ {
+ return $self->at(key);
+ }
+
+ void __setitem__(const Key & key, const T & value)
+ {
+ $self->operator[](key) = value;
+ }
+
+ void __delitem__(const Key & key)
+ {
+ if ($self->erase(key) == 0)
+ throw std::out_of_range("PreserveOrderMap::__delitem__");
+ }
+
+ bool __contains__(const Key & key) const
+ {
+ return $self->count(key) > 0;
+ }
+
+ size_t __len__() const
+ {
+ return $self->size();
+ }
+ }
+%enddef
+EXTEND_TEMPLATE_PreserveOrderMap(T, std::string, std::string)
+EXTEND_TEMPLATE_PreserveOrderMap(T &, std::string, libdnf::PreserveOrderMap<std::string, std::string>)
+
+%template(PreserveOrderMapStringString) libdnf::PreserveOrderMap<std::string, std::string>;
+%template(PreserveOrderMapStringStringIterator) Iterator<libdnf::PreserveOrderMap<std::string, std::string>>;
+%template(PreserveOrderMapStringPreserveOrderMapStringString) libdnf::PreserveOrderMap<std::string, libdnf::PreserveOrderMap<std::string, std::string>>;
+%template(PreserveOrderMapStringPreserveOrderMapStringStringIterator) Iterator<libdnf::PreserveOrderMap<std::string, libdnf::PreserveOrderMap<std::string, std::string>>>;
+
+
+%exception __next__() {
+ try
+ {
+ $action // calls %extend function next() below
+ }
+ catch (StopIterator)
+ {
+ PyErr_SetString(PyExc_StopIteration, "End of iterator");
+ return NULL;
+ }
+}
+
+// For old Python
+%exception next() {
+ try
+ {
+ $action // calls %extend function next() below
+ }
+ catch (StopIterator)
+ {
+ PyErr_SetString(PyExc_StopIteration, "End of iterator");
+ return NULL;
+ }
+}
+
+%define EXTEND_TEMPLATE_PreserveOrderMapIterator(Key, T...)
+%extend Iterator<libdnf::PreserveOrderMap<Key, T>> {
+ Key __next__()
+ {
+ if ($self->cur != $self->end) {
+ return ($self->cur++)->first;
+ }
+ throw StopIterator();
+ }
+ Key next()
+ {
+ if ($self->cur != $self->end) {
+ return ($self->cur++)->first;
+ }
+ throw StopIterator();
+ }
+}
+
+%extend libdnf::PreserveOrderMap<Key, T> {
+ Iterator<libdnf::PreserveOrderMap<Key, T>> __iter__()
+ {
+ return Iterator<libdnf::PreserveOrderMap<Key, T>>($self->begin(), $self->end());
+ }
+}
+%enddef
+EXTEND_TEMPLATE_PreserveOrderMapIterator(std::string, std::string)
+EXTEND_TEMPLATE_PreserveOrderMapIterator(std::string, libdnf::PreserveOrderMap<std::string, std::string>)
+
+%exception; // beware this resets all exception handlers if you import this file after defining any
--- /dev/null
+%module conf
+
+%include <exception.i>
+%include <stdint.i>
+%include <std_map.i>
+%include <std_pair.i>
+
+%import(module="libdnf.common_types") "common_types.i"
+
+%begin %{
+ #define SWIG_PYTHON_2_UNICODE
+%}
+
+%{
+ // make SWIG wrap following headers
+ #include "libdnf/conf/ConfigRepo.hpp"
+ #include "libdnf/conf/ConfigParser.hpp"
+ #include <iterator>
+ #include <memory>
+ #include <sstream>
+%}
+
+// Using catch_error.i doesnt work here, because it translates
+// std::out_of_range to SWIG_IndexError and the DNF code seems to be relying on
+// it actually being a SWIG_RuntimeError here, which is obviously very wrong.
+%exception {
+ try {
+ $action
+ } catch (const std::exception & e) {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+#define final
+
+// make SWIG look into following headers
+%ignore libdnf::Option::Exception;
+%ignore libdnf::Option::InvalidValue;
+%ignore libdnf::Option::ValueNotSet;
+%include "libdnf/conf/Option.hpp"
+%include "libdnf/conf/OptionChild.hpp"
+%include "libdnf/conf/OptionBool.hpp"
+%include "libdnf/conf/OptionEnum.hpp"
+%template(OptionEnumString) libdnf::OptionEnum<std::string>;
+%include "libdnf/conf/OptionNumber.hpp"
+%template(OptionNumberInt32) libdnf::OptionNumber<std::int32_t>;
+%template(OptionNumberUInt32) libdnf::OptionNumber<std::uint32_t>;
+%template(OptionNumberInt64) libdnf::OptionNumber<std::int64_t>;
+%template(OptionNumberUInt64) libdnf::OptionNumber<std::uint64_t>;
+%template(OptionNumberFloat) libdnf::OptionNumber<float>;
+%include "libdnf/conf/OptionSeconds.hpp"
+%include "libdnf/conf/OptionString.hpp"
+%include "libdnf/conf/OptionStringList.hpp"
+%include "libdnf/conf/OptionPath.hpp"
+
+%template(OptionChildBool) libdnf::OptionChild<libdnf::OptionBool>;
+%template(OptionChildString) libdnf::OptionChild<libdnf::OptionString>;
+%template(OptionChildStringList) libdnf::OptionChild<libdnf::OptionStringList>;
+%template(OptionChildNumberInt32) libdnf::OptionChild<libdnf::OptionNumber<std::int32_t>>;
+%template(OptionChildNumberUInt32) libdnf::OptionChild<libdnf::OptionNumber<std::uint32_t>>;
+%template(OptionChildNumberFloat) libdnf::OptionChild<libdnf::OptionNumber<float>>;
+%template(OptionChildEnumString) libdnf::OptionChild<libdnf::OptionEnum<std::string>>;
+%template(OptionChildSeconds) libdnf::OptionChild<libdnf::OptionSeconds>;
+
+%include <std_vector_ext.i>
+
+%inline %{
+class StopIterator {};
+
+template<class T>
+class Iterator {
+public:
+ Iterator(typename T::iterator _cur, typename T::iterator _end) : cur(_cur), end(_end) {}
+ Iterator* __iter__()
+ {
+ return this;
+ }
+
+ typename T::iterator cur;
+ typename T::iterator end;
+ };
+%}
+
+%feature ("flatnested", "1");
+%rename (OptionBinds_Item) libdnf::OptionBinds::Item;
+%ignore libdnf::OptionBinds::Exception;
+%ignore libdnf::OptionBinds::OutOfRange;
+%ignore libdnf::OptionBinds::AlreadyExists;
+%ignore libdnf::OptionBinds::add(const std::string & id, Option & option,
+ const Item::NewStringFunc & newString, const Item::GetValueStringFunc & getValueString, bool addValue);
+%ignore libdnf::OptionBinds::add(const std::string & id, Option & option,
+ Item::NewStringFunc && newString, Item::GetValueStringFunc && getValueString, bool addValue);
+%ignore libdnf::OptionBinds::begin;
+%ignore libdnf::OptionBinds::cbegin;
+%ignore libdnf::OptionBinds::end;
+%ignore libdnf::OptionBinds::cend;
+%ignore libdnf::OptionBinds::find;
+%include "libdnf/conf/OptionBinds.hpp"
+%feature ("flatnested", "0");
+
+%include "libdnf/conf/Config.hpp"
+%include "libdnf/conf/ConfigMain.hpp"
+%include "libdnf/conf/ConfigRepo.hpp"
+
+%template(OptionBindsIterator) Iterator<libdnf::OptionBinds>;
+
+%exception libdnf::ConfigParser::read {
+ try
+ {
+ $action
+ }
+ catch (const libdnf::ConfigParser::CantOpenFile & e)
+ {
+ SWIG_exception(SWIG_IOError, e.what());
+ }
+ catch (const libdnf::ConfigParser::Exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%exception libdnf::ConfigParser::getValue {
+ try
+ {
+ $action
+ }
+ catch (const libdnf::ConfigParser::MissingSection & e)
+ {
+ SWIG_exception(SWIG_IndexError, e.what());
+ }
+ catch (const libdnf::ConfigParser::MissingOption & e)
+ {
+ SWIG_exception(SWIG_IndexError, e.what());
+ }
+ catch (const libdnf::ConfigParser::Exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%exception libdnf::ConfigParser::getSubstitutedValue {
+ try
+ {
+ $action
+ }
+ catch (const libdnf::ConfigParser::MissingSection & e)
+ {
+ SWIG_exception(SWIG_IndexError, e.what());
+ }
+ catch (const libdnf::ConfigParser::MissingOption & e)
+ {
+ SWIG_exception(SWIG_IndexError, e.what());
+ }
+ catch (const libdnf::ConfigParser::Exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%apply std::string & INOUT { std::string & text }
+namespace libdnf {
+struct ConfigParser {
+public:
+ typedef PreserveOrderMap<std::string, PreserveOrderMap<std::string, std::string>> Container;
+
+ static void substitute(std::string & text,
+ const std::map<std::string, std::string> & substitutions);
+ void setSubstitutions(const std::map<std::string, std::string> & substitutions);
+ const std::map<std::string, std::string> & getSubstitutions() const;
+ void read(const std::string & filePath);
+ void write(const std::string & filePath, bool append) const;
+ void write(const std::string & filePath, bool append, const std::string & section) const;
+ void write(std::ostream & outputStream, const std::string & section) const;
+ void write(std::ostream & outputStream) const;
+ bool addSection(const std::string & section, const std::string & rawLine);
+ bool addSection(const std::string & section);
+ bool hasSection(const std::string & section) const noexcept;
+ bool hasOption(const std::string & section, const std::string & key) const noexcept;
+ void setValue(const std::string & section, const std::string & key, const std::string & value, const std::string & rawItem);
+ void setValue(const std::string & section, const std::string & key, const std::string & value);
+ bool removeSection(const std::string & section);
+ bool removeOption(const std::string & section, const std::string & key);
+ void addCommentLine(const std::string & section, const std::string & comment);
+ const std::string & getValue(const std::string & section, const std::string & key) const;
+ std::string getSubstitutedValue(const std::string & section, const std::string & key) const;
+ const std::string & getHeader() const noexcept;
+ std::string & getHeader() noexcept;
+ const Container & getData() const noexcept;
+ Container & getData() noexcept;
+};
+}
+%clear std::string & text;
+
+%extend libdnf::ConfigParser {
+ void readString(const std::string & content) {
+ std::unique_ptr<std::istringstream> istream(new std::istringstream(content));
+ self->read(std::move(istream));
+ }
+}
+
+%exception __next__() {
+ try
+ {
+ $action // calls %extend function next() below
+ }
+ catch (const StopIterator &)
+ {
+ PyErr_SetString(PyExc_StopIteration, "End of iterator");
+ return NULL;
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+// For old Python
+%exception next() {
+ try
+ {
+ $action // calls %extend function next() below
+ }
+ catch (const StopIterator &)
+ {
+ PyErr_SetString(PyExc_StopIteration, "End of iterator");
+ return NULL;
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%template(PairStringOptionBindsItem) std::pair<std::string, libdnf::OptionBinds::Item *>;
+%extend Iterator<libdnf::OptionBinds> {
+ std::pair<std::string, libdnf::OptionBinds::Item *> __next__()
+ {
+ if ($self->cur != $self->end) {
+ auto & id = $self->cur->first;
+ auto pValue = &($self->cur++)->second;
+ return {id, pValue};
+ }
+ throw StopIterator();
+ }
+ std::pair<std::string, libdnf::OptionBinds::Item *> next()
+ {
+ if ($self->cur != $self->end) {
+ auto & id = $self->cur->first;
+ auto pValue = &($self->cur++)->second;
+ return {id, pValue};
+ }
+ throw StopIterator();
+ }
+}
+
+%exception libdnf::OptionBinds::__getitem__ {
+ try
+ {
+ $action
+ }
+ catch (const libdnf::OptionBinds::OutOfRange & e)
+ {
+ SWIG_exception(SWIG_IndexError, e.what());
+ }
+ catch (const std::exception & e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%extend libdnf::OptionBinds {
+ Item & __getitem__(const std::string & id)
+ {
+ return $self->at(id);
+ }
+
+ size_t __len__()
+ {
+ return $self->size();
+ }
+
+ Iterator<libdnf::OptionBinds> __iter__()
+ {
+ return Iterator<libdnf::OptionBinds>($self->begin(), $self->end());
+ }
+}
+
+%pythoncode %{
+# Partial compatibility with Python ConfigParser
+ConfigParser.readFileName = ConfigParser.read
+def ConfigParser__newRead(self, filenames):
+ parsedFNames = []
+ try:
+ if isinstance(filenames, str) or isinstance(filenames, unicode):
+ filenames = [filenames]
+ except NameError:
+ pass
+ for fname in filenames:
+ try:
+ self.readFileName(fname)
+ parsedFNames.append(fname)
+ except IOError:
+ pass
+ except Exception as e:
+ raise RuntimeError("Parsing file '%s' failed: %s" % (fname, str(e)))
+ return parsedFNames
+ConfigParser.read = ConfigParser__newRead
+del ConfigParser__newRead
+
+def ConfigParser__read_string(self, string, source='<string>'):
+ try:
+ self.readString(string)
+ except Exception as e:
+ raise RuntimeError("Parsing source '%s' failed: %s" % (source, str(e)))
+ConfigParser.read_string = ConfigParser__read_string
+del ConfigParser__read_string
+
+def ConfigParser__add_section(self, section):
+ if not self.addSection(section):
+ raise KeyError("Section '%s' already exists" % section)
+ConfigParser.add_section = ConfigParser__add_section
+del ConfigParser__add_section
+
+ConfigParser.has_section = ConfigParser.hasSection
+ConfigParser.has_option = ConfigParser.hasOption
+
+def ConfigParser__get(self, section, option, raw=False):
+ try:
+ if raw:
+ return self.getValue(section, option)
+ else:
+ return self.getSubstitutedValue(section, option)
+ except IndexError as e:
+ raise KeyError(str(e))
+
+ConfigParser.get = ConfigParser__get
+del ConfigParser__get
+
+def ConfigParser__getint(self, section, option, raw=False):
+ return int(self.get(section, option, raw=raw))
+ConfigParser.getint = ConfigParser__getint
+del ConfigParser__getint
+
+def ConfigParser__getfloat(self, section, option, raw=False):
+ return float(self.get(section, option, raw=raw))
+ConfigParser.getfloat = ConfigParser__getfloat
+del ConfigParser__getfloat
+
+def ConfigParser__getboolean(self, section, option, raw=False):
+ v = self.get(section, option, raw=raw)
+ try:
+ return OptionBool(False).fromString(v)
+ except RuntimeError:
+ raise ValueError('Not a boolean: %s' % v)
+ConfigParser.getboolean = ConfigParser__getboolean
+del ConfigParser__getboolean
+
+def ConfigParser__items(self, section, raw=False):
+ if not self.hasSection(section):
+ raise KeyError("No section: '%s'" % section)
+ sectObj = self.getData()[section]
+ items = []
+ for key in sectObj:
+ if not key.startswith('#'):
+ value = self.get(section, key, raw=raw)
+ items.append((key, value))
+ return items
+ConfigParser.items = ConfigParser__items
+del ConfigParser__items
+
+def ConfigParser__set(self, section, option, value):
+ if not self.hasSection(section):
+ raise KeyError("No section: '%s'" % section)
+ self.setValue(section, option, value)
+ConfigParser.set = ConfigParser__set
+del ConfigParser__set
+
+ConfigParser.remove_section = ConfigParser.removeSection
+
+def ConfigParser__remove_option(self, section, option):
+ if not self.hasSection(section):
+ raise KeyError("No section: '%s'" % section)
+ return self.removeOption(section, option)
+ConfigParser.remove_option = ConfigParser__remove_option
+del ConfigParser__remove_option
+
+def ConfigParser__options(self, section):
+ if not self.hasSection(section):
+ raise KeyError("No section: '%s'" % section)
+ sectObj = self.getData()[section]
+ return [item for item in sectObj if not item.startswith('#')]
+ConfigParser.options = ConfigParser__options
+del ConfigParser__options
+
+def ConfigParser__sections(self):
+ return list(self.getData())
+ConfigParser.sections = ConfigParser__sections
+del ConfigParser__sections
+
+# Compatible name aliases
+ConfigMain.exclude = ConfigMain.excludepkgs
+ConfigRepo.exclude = ConfigRepo.excludepkgs
+%}
--- /dev/null
+%module error
+
+%{
+ #include "libdnf/error.hpp"
+ #define SWIG_FILE_WITH_INIT
+ PyObject* libdnf_error;
+%}
+
+%init %{
+ libdnf_error = PyErr_NewException("libdnf._error.Error", NULL, NULL);
+ Py_INCREF(libdnf_error);
+ PyModule_AddObject(m, "Error", libdnf_error);
+%}
+
+%pythoncode %{
+ Error = _error.Error
+%}
--- /dev/null
+%module module
+
+%begin %{
+#define SWIG_PYTHON_2_UNICODE
+%}
+
+#define DEPRECATED(x)
+
+%include <std_map.i>
+%include <std_pair.i>
+%include <std_vector.i>
+%include <std_string.i>
+
+%import(module="libdnf.common_types") "common_types.i"
+
+%include "catch_error.i"
+
+typedef int Id;
+
+%{
+ // make SWIG wrap following headers
+ #include "libdnf/module/ModulePackageContainer.hpp"
+%}
+
+%inline %{
+ typedef libdnf::ModuleDependencies ModuleDependencies;
+ typedef libdnf::ModuleProfile ModuleProfile;
+%}
+
+%extend libdnf::ModulePackage {
+ long __hash__()
+ {
+ return $self->getId();
+ }
+}
+
+%template(VectorModulePackagePtr) std::vector<libdnf::ModulePackage *>;
+%template(VectorVectorVectorModulePackagePtr) std::vector<std::vector<std::vector<libdnf::ModulePackage *>>>;
+%template(VectorModuleProfile) std::vector<libdnf::ModuleProfile>;
+%template(VectorModuleDependencies) std::vector<ModuleDependencies>;
+
+%include <std_vector_ext.i>
+
+// this must follow std_vector_ext.i include, otherwise it returns garbage instead of list of strings
+%template(MapStringVectorString) std::map<std::string, std::vector<std::string>>;
+%template(VectorMapStringVectorString) std::vector<std::map<std::string, std::vector<std::string>>>;
+%template(VectorVectorString) std::vector<std::vector<std::string>>;
+
+// make SWIG wrap following headers
+%nodefaultctor libdnf::ModulePackage;
+%nodefaultctor libdnf::ModuleProfile;
+%nodefaultctor libdnf::ModuleDependencies;
+
+%include "libdnf/module/ModulePackage.hpp"
+%ignore libdnf::ModulePackageContainer::Exception;
+%ignore libdnf::ModulePackageContainer::NoModuleException;
+%ignore libdnf::ModulePackageContainer::NoStreamException;
+%ignore libdnf::ModulePackageContainer::EnabledStreamException;
+%ignore libdnf::ModulePackageContainer::EnableMultipleStreamsException;
+%include "libdnf/module/ModulePackageContainer.hpp"
+%include "libdnf/module/modulemd/ModuleProfile.hpp"
+%include "libdnf/module/modulemd/ModuleDependencies.hpp"
+%template(PairVectorVectorStringModuleErrorType) std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer::ModuleErrorType>;
--- /dev/null
+%module(directors="1") repo
+
+%include <stdint.i>
+%include <std_vector.i>
+%include <std_string.i>
+
+%import(module="libdnf.common_types") "common_types.i"
+%import(module="libdnf.conf") "conf.i"
+
+%include "catch_error.i"
+
+%begin %{
+ #define SWIG_PYTHON_2_UNICODE
+%}
+
+%{
+ // make SWIG wrap following headers
+ #include "libdnf/repo/Crypto.hpp"
+ #include "libdnf/repo/Repo.hpp"
+%}
+
+// make SWIG look into following headers
+%template(VectorPPackageTarget) std::vector<libdnf::PackageTarget *>;
+
+%extend libdnf::Repo {
+ Repo(const std::string & id, ConfigRepo * config)
+ {
+ return new libdnf::Repo(id, std::unique_ptr<libdnf::ConfigRepo>(config));
+ }
+ void setCallbacks(RepoCB * callbacks)
+ {
+ self->setCallbacks(std::unique_ptr<libdnf::RepoCB>(callbacks));
+ }
+ void setHttpHeaders(const std::vector<std::string> & headers)
+ {
+ const char * cHeaders[headers.size() + 1];
+ for (size_t i = 0; i < headers.size(); ++i)
+ cHeaders[i] = headers[i].c_str();
+ cHeaders[headers.size()] = nullptr;
+ self->setHttpHeaders(cHeaders);
+ }
+ std::vector<std::string> getHttpHeaders() const
+ {
+ auto cHeaders = self->getHttpHeaders();
+ if (!cHeaders)
+ return {};
+ size_t headersCount = 0;
+ while (cHeaders[headersCount])
+ ++headersCount;
+ std::vector<std::string> headers(headersCount);
+ for (size_t i = 0; i < headersCount; ++i) {
+ headers[i] = cHeaders[i];
+ }
+ return headers;
+ }
+}
+%ignore libdnf::Repo::Repo;
+%ignore libdnf::Repo::setCallbacks;
+%ignore libdnf::Repo::setHttpHeaders;
+%ignore libdnf::Repo::getHttpHeaders;
+
+%extend libdnf::PackageTarget {
+ PackageTarget(ConfigMain * cfg, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const std::vector<std::string> & httpHeaders = {})
+ {
+ const char * cHeaders[httpHeaders.size() + 1];
+ for (size_t i = 0; i < httpHeaders.size(); ++i)
+ cHeaders[i] = httpHeaders[i].c_str();
+ cHeaders[httpHeaders.size()] = nullptr;
+
+ return new libdnf::PackageTarget(cfg, relativeUrl, dest, chksType,
+ chksum, expectedSize, baseUrl, resume,
+ byteRangeStart, byteRangeEnd, callbacks,
+ httpHeaders.size() > 0 ? cHeaders : nullptr);
+ }
+}
+%ignore libdnf::PackageTarget::PackageTarget(ConfigMain * cfg, const char * relativeUrl,
+ const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const char * httpHeaders[] = nullptr);
+
+%ignore std::vector<libdnf::Key>::vector(size_type);
+%ignore std::vector<libdnf::Key>::resize;
+%template(VectorKey) std::vector<libdnf::Key>;
+%include "libdnf/repo/Crypto.hpp"
+
+%feature("director") libdnf::RepoCB;
+%ignore libdnf::PackageTarget::PackageTarget(const PackageTarget & src);
+%feature("director") libdnf::PackageTargetCB;
+%include "libdnf/repo/Repo.hpp"
--- /dev/null
+%module smartcols
+
+%include <std_shared_ptr.i>
+%include <std_string.i>
+
+%include "catch_error.i"
+
+%{
+// make SWIG wrap following headers
+#include "libdnf/utils/smartcols/Table.hpp"
+#include "libdnf/utils/smartcols/Column.hpp"
+#include "libdnf/utils/smartcols/Line.hpp"
+#include "libdnf/utils/smartcols/Cell.hpp"
+%}
+
+%rename(_print) print;
+
+%shared_ptr(Column)
+%shared_ptr(Line)
+%shared_ptr(Cell)
+%shared_ptr(Table)
+
+%include "libdnf/utils/smartcols/Table.hpp"
+%include "libdnf/utils/smartcols/Column.hpp"
+%include "libdnf/utils/smartcols/Line.hpp"
+%include "libdnf/utils/smartcols/Cell.hpp"
--- /dev/null
+%include <std_vector.i>
+%include <std_string.i>
+
+
+%template(VectorString) std::vector<std::string>;
+
+%pythoncode %{
+
+def VectorString__str__(self):
+ return str(list(self))
+VectorString.__str__ = VectorString__str__
+
+def VectorString__eq__(self, other):
+ return list(self) == list(other)
+VectorString.__eq__ = VectorString__eq__
+
+def VectorString__ne__(self, other):
+ return list(self) != list(other)
+VectorString.__ne__ = VectorString__ne__
+
+def VectorString__lt__(self, other):
+ return list(self) < list(other)
+VectorString.__lt__ = VectorString__lt__
+
+def VectorString__le__(self, other):
+ return list(self) <= list(other)
+VectorString.__le__ = VectorString__le__
+
+def VectorString__gt__(self, other):
+ return list(self) > list(other)
+VectorString.__gt__ = VectorString__gt__
+
+def VectorString__ge__(self, other):
+ return list(self) >= list(other)
+VectorString.__ge__ = VectorString__ge__
+
+def VectorString__iadd__(self, value):
+ self.extend(value)
+ return self
+VectorString.__iadd__ = VectorString__iadd__
+
+def VectorString__imul__(self, value):
+ data = list(self)
+ data *= value
+ self.clear()
+ self.extend(data)
+ return self
+VectorString.__imul__ = VectorString__imul__
+
+def VectorString__mul__(self, value):
+ result = self.copy()
+ result *= value
+ return result
+VectorString.__mul__ = VectorString__mul__
+
+def VectorString__rmul__(self, value):
+ return self * value
+VectorString.__rmul__ = VectorString__rmul__
+
+def VectorString__add__(self, value):
+ result = self.copy()
+ result.extend(value)
+ return result
+VectorString.__add__ = VectorString__add__
+
+def VectorString__append(self, item):
+ self.push_back(item)
+VectorString.append = VectorString__append
+
+def VectorString__copy(self):
+ return VectorString(list(self))
+VectorString.copy = VectorString__copy
+
+def VectorString__count(self, item):
+ return list(self).count(item)
+VectorString.count = VectorString__count
+
+def VectorString__extend(self, iterable):
+ for i in iterable:
+ self.push_back(i)
+VectorString.extend = VectorString__extend
+
+def VectorString__index(self, *args, **kwargs):
+ data = list(self)
+ return data.index(*args, **kwargs)
+VectorString.index = VectorString__index
+
+def VectorString__insert(self, *args, **kwargs):
+ data = list(self)
+ data.insert(*args, **kwargs)
+ self.clear()
+ self.extend(data)
+VectorString.insert = VectorString__insert
+
+def VectorString__remove(self, *args, **kwargs):
+ data = list(self)
+ data.remove(*args, **kwargs)
+ self.clear()
+ self.extend(data)
+VectorString.remove = VectorString__remove
+
+def VectorString__sort(self, *args, **kwargs):
+ data = list(self)
+ data.sort()
+ self.clear()
+ self.extend(data)
+VectorString.sort = VectorString__sort
+
+def VectorString__reverse(self, *args, **kwargs):
+ data = list(self)
+ data.reverse()
+ self.clear()
+ self.extend(data)
+VectorString.reverse = VectorString__reverse
+%}
--- /dev/null
+%module transaction
+
+%begin %{
+#define SWIG_PYTHON_2_UNICODE
+%}
+
+%include <std_map.i>
+%include <std_pair.i>
+%include <std_shared_ptr.i>
+%include <std_string.i>
+%include <std_vector.i>
+%include <stdint.i>
+%include <typemaps.i>
+
+%include "catch_error.i"
+
+%rename ("__hash__", fullname=1) "libdnf::TransactionItem::getHash";
+
+%shared_ptr(SQLite3)
+typedef std::shared_ptr< SQLite3 > SQLite3Ptr;
+
+%shared_ptr(libdnf::Item)
+typedef std::shared_ptr< libdnf::Item > ItemPtr;
+
+%shared_ptr(libdnf::RPMItem)
+typedef std::shared_ptr< libdnf::RPMItem > RPMItemPtr;
+
+%shared_ptr(libdnf::CompsGroupItem)
+typedef std::shared_ptr< libdnf::CompsGroupItem > CompsGroupItemPtr;
+
+%shared_ptr(libdnf::CompsGroupPackage)
+typedef std::shared_ptr< libdnf::CompsGroupPackage > CompsGroupPackagePtr;
+
+%shared_ptr(libdnf::CompsEnvironmentItem)
+typedef std::shared_ptr< libdnf::CompsEnvironmentItem > CompsEnvironmentItemPtr;
+
+%shared_ptr(libdnf::CompsEnvironmentGroup)
+typedef std::shared_ptr< libdnf::CompsEnvironmentGroup > CompsEnvironmentGroupPtr;
+
+%shared_ptr(libdnf::Transaction)
+typedef std::shared_ptr< libdnf::Transaction > TransactionPtr;
+
+%shared_ptr(libdnf::TransactionItem)
+typedef std::shared_ptr< libdnf::TransactionItem > TransactionItemPtr;
+
+%shared_ptr(libdnf::MergedTransaction)
+typedef std::shared_ptr< libdnf::MergedTransaction > MergedTransactionPtr;
+
+%shared_ptr(libdnf::TransactionItemBase)
+typedef std::shared_ptr< libdnf::TransactionItemBase > TransactionItemBasePtr;
+
+// XXX workaround - because SWIG...
+typedef libdnf::CompsPackageType CompsPackageType;
+
+%{
+ // make SWIG wrap following headers
+ #include "libdnf/transaction/Item.hpp"
+ #include "libdnf/transaction/CompsEnvironmentItem.hpp"
+ #include "libdnf/transaction/CompsGroupItem.hpp"
+ #include "libdnf/transaction/RPMItem.hpp"
+ #include "libdnf/transaction/Swdb.hpp"
+ #include "libdnf/transaction/Transaction.hpp"
+ #include "libdnf/transaction/TransactionItem.hpp"
+ #include "libdnf/transaction/TransactionItemReason.hpp"
+ #include "libdnf/transaction/MergedTransaction.hpp"
+ #include "libdnf/transaction/Transformer.hpp"
+ #include "libdnf/transaction/Types.hpp"
+ using namespace libdnf;
+%}
+
+
+// This include has to be before %template definitions. SWIG is fragile :(
+%include "libdnf/transaction/TransactionItemReason.hpp"
+%include "libdnf/transaction/Types.hpp"
+
+
+%template() std::vector<std::shared_ptr<libdnf::Transaction> >;
+%template() std::vector<std::shared_ptr<libdnf::TransactionItem> >;
+%template() std::vector<std::shared_ptr<libdnf::TransactionItemBase> >;
+%template() std::vector<std::shared_ptr<libdnf::CompsGroupPackage> >;
+%template() std::vector<std::shared_ptr<libdnf::CompsEnvironmentGroup> >;
+%template(TransactionStateVector) std::vector<libdnf::TransactionState>;
+
+%template() std::vector<uint32_t>;
+%template() std::vector<int64_t>;
+%template() std::vector<bool>;
+
+%template() std::vector< std::string >;
+%template() std::pair<int,std::string>;
+%template() std::map<std::string,int>;
+%template() std::map<std::string,std::string>;
+%template() std::vector<std::pair<int,std::string> >;
+
+
+// make SWIG look into following headers
+%include "libdnf/transaction/Item.hpp"
+%include "libdnf/transaction/CompsEnvironmentItem.hpp"
+%include "libdnf/transaction/CompsGroupItem.hpp"
+%include "libdnf/transaction/RPMItem.hpp"
+%include "libdnf/transaction/Swdb.hpp"
+%include "libdnf/transaction/Transaction.hpp"
+%include "libdnf/transaction/TransactionItem.hpp"
+%include "libdnf/transaction/MergedTransaction.hpp"
+%include "libdnf/transaction/Transformer.hpp"
--- /dev/null
+%module(directors="1") utils
+
+%begin %{
+#define SWIG_PYTHON_2_UNICODE
+%}
+
+%include <std_shared_ptr.i>
+%include <std_string.i>
+
+%include "catch_error.i"
+
+%{
+ // make SWIG wrap following headers
+ #include "libdnf/utils/sqlite3/Sqlite3.hpp"
+ #include "libdnf/utils/logger.hpp"
+ #include "libdnf/log.hpp"
+ #include "libdnf/utils/utils.hpp"
+%}
+
+%shared_ptr(SQLite3)
+%nocopyctor SQLite3;
+
+
+// make SWIG look into following headers
+class SQLite3 {
+public:
+ SQLite3(const SQLite3 &) = delete;
+ SQLite3 & operator=(const SQLite3 &) = delete;
+ SQLite3(const char *dbPath);
+ void close();
+};
+
+typedef long time_t;
+typedef long pid_t;
+
+%feature("director") Logger;
+%include "libdnf/utils/logger.hpp"
+
+%include "libdnf/log.hpp"
+
+typedef int mode_t;
+
+namespace libdnf { namespace filesystem {
+
+void decompress(const char * inPath, const char * outPath, mode_t outMode, const char * compressType = nullptr);
+
+bool checksum_check(const char * type, const char * inPath, const char * checksum_valid);
+std::string checksum_value(const char * type, const char * inPath);
+
+}}
--- /dev/null
+# - SWIG module for CMake
+# Defines the following macros:
+# SWIG_ADD_MODULE(name language [ files ])
+# - Define swig module with given name and specified language
+# SWIG_LINK_LIBRARIES(name [ libraries ])
+# - Link libraries to swig module
+# All other macros are for internal use only.
+# To get the actual name of the swig module,
+# use: ${SWIG_MODULE_${name}_REAL_NAME}.
+# Set Source files properties such as CPLUSPLUS and SWIG_FLAGS to specify
+# special behavior of SWIG. Also global CMAKE_SWIG_FLAGS can be used to add
+# special flags to all swig calls.
+# Another special variable is CMAKE_SWIG_OUTDIR, it allows one to specify
+# where to write all the swig generated module (swig -outdir option)
+# The name-specific variable SWIG_MODULE_<name>_EXTRA_DEPS may be used
+# to specify extra dependencies for the generated modules.
+# If the source file generated by swig need some special flag you can use
+# set_source_files_properties( ${swig_generated_file_fullname}
+# PROPERTIES COMPILE_FLAGS "-bla")
+
+#=============================================================================
+# Copyright 2004-2009 Kitware, Inc.
+# Copyright 2009 Mathieu Malaterre <mathieu.malaterre@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+set(SWIG_CXX_EXTENSION "cxx")
+set(SWIG_EXTRA_LIBRARIES "")
+
+set(SWIG_PYTHON_EXTRA_FILE_EXTENSION "py")
+
+#
+# For given swig module initialize variables associated with it
+#
+macro(SWIG_MODULE_INITIALIZE name language)
+ string(TOUPPER "${language}" swig_uppercase_language)
+ string(TOLOWER "${language}" swig_lowercase_language)
+ set(SWIG_MODULE_${name}_LANGUAGE "${swig_uppercase_language}")
+ set(SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG "${swig_lowercase_language}")
+
+ set(SWIG_MODULE_${name}_REAL_NAME "${name}")
+ if("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "UNKNOWN")
+ message(FATAL_ERROR "SWIG Error: Language \"${language}\" not found")
+ elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PYTHON")
+ # when swig is used without the -interface it will produce in the module.py
+ # a 'import _modulename' statement, which implies having a corresponding
+ # _modulename.so (*NIX), _modulename.pyd (Win32).
+ set(SWIG_MODULE_${name}_REAL_NAME "_${name}")
+ elseif("${SWIG_MODULE_${name}_LANGUAGE}" STREQUAL "PERL")
+ set(SWIG_MODULE_${name}_EXTRA_FLAGS "-shadow")
+ endif()
+endmacro()
+
+#
+# For a given language, input file, and output file, determine extra files that
+# will be generated. This is internal swig macro.
+#
+
+macro(SWIG_GET_EXTRA_OUTPUT_FILES language outfiles generatedpath infile)
+ set(${outfiles} "")
+ get_source_file_property(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename
+ ${infile} SWIG_MODULE_NAME)
+ if(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename STREQUAL "NOTFOUND")
+ get_filename_component(SWIG_GET_EXTRA_OUTPUT_FILES_module_basename "${infile}" NAME_WE)
+ endif()
+ foreach(it ${SWIG_${language}_EXTRA_FILE_EXTENSION})
+ set(${outfiles} ${${outfiles}}
+ "${generatedpath}/${SWIG_GET_EXTRA_OUTPUT_FILES_module_basename}.${it}")
+ endforeach()
+endmacro()
+
+#
+# Take swig (*.i) file and add proper custom commands for it
+#
+macro(SWIG_ADD_SOURCE_TO_MODULE name outfiles infile)
+ set(swig_full_infile ${infile})
+ get_filename_component(swig_source_file_path "${infile}" PATH)
+ get_filename_component(swig_source_file_name_we "${infile}" NAME_WE)
+ get_source_file_property(swig_source_file_generated ${infile} GENERATED)
+ get_source_file_property(swig_source_file_cplusplus ${infile} CPLUSPLUS)
+ get_source_file_property(swig_source_file_flags ${infile} SWIG_FLAGS)
+ if("${swig_source_file_flags}" STREQUAL "NOTFOUND")
+ set(swig_source_file_flags "")
+ endif()
+ set(swig_source_file_fullname "${infile}")
+ if(IS_ABSOLUTE "${swig_source_file_path}")
+ if("${swig_source_file_path}" MATCHES "^${CMAKE_CURRENT_SOURCE_DIR}")
+ string(REGEX REPLACE
+ "^${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
+ swig_generated_file_path
+ "${swig_source_file_path}")
+ elseif("${swig_source_file_path}" MATCHES "^${CMAKE_CURRENT_BINARY_DIR}")
+ set(swig_generated_file_path "${swig_source_file_path}")
+ else()
+ # Avoid having a really deep path.
+ set(swig_generated_file_path "${CMAKE_CURRENT_BINARY_DIR}/swig-sources")
+ endif()
+ else()
+ # Source file is relative to the cmake current source dir.
+ string(REPLACE ".." "__" parent_free_path "${swig_source_file_path}")
+ set(swig_generated_file_path "${CMAKE_CURRENT_BINARY_DIR}/${parent_free_path}")
+ set(swig_source_file_fullname "${CMAKE_CURRENT_SOURCE_DIR}/${infile}")
+ endif()
+
+ # If CMAKE_SWIG_OUTDIR was specified then pass it to -outdir
+ if(CMAKE_SWIG_OUTDIR)
+ set(swig_outdir ${CMAKE_SWIG_OUTDIR})
+ else()
+ set(swig_outdir ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+ SWIG_GET_EXTRA_OUTPUT_FILES(${SWIG_MODULE_${name}_LANGUAGE}
+ swig_extra_generated_files
+ "${swig_outdir}"
+ "${swig_source_file_fullname}")
+ set(swig_generated_file_fullname
+ "${swig_generated_file_path}/${swig_source_file_name_we}")
+ # add the language into the name of the file (i.e. TCL_wrap)
+ # this allows for the same .i file to be wrapped into different languages
+ set(swig_generated_file_fullname
+ "${swig_generated_file_fullname}${SWIG_MODULE_${name}_LANGUAGE}_wrap")
+
+ if(swig_source_file_cplusplus)
+ set(swig_generated_file_fullname
+ "${swig_generated_file_fullname}.${SWIG_CXX_EXTENSION}")
+ else()
+ set(swig_generated_file_fullname
+ "${swig_generated_file_fullname}.c")
+ endif()
+
+ #message("Full path to source file: ${swig_source_file_fullname}")
+ #message("Full path to the output file: ${swig_generated_file_fullname}")
+ get_directory_property(cmake_include_directories INCLUDE_DIRECTORIES)
+ set(swig_include_dirs)
+ foreach(it ${cmake_include_directories})
+ set(swig_include_dirs ${swig_include_dirs} "-I${it}")
+ endforeach()
+
+ set(swig_special_flags)
+ # default is c, so add c++ flag if it is c++
+ if(swig_source_file_cplusplus)
+ set(swig_special_flags ${swig_special_flags} "-c++")
+ endif()
+ set(swig_extra_flags)
+ if(SWIG_MODULE_${name}_EXTRA_FLAGS)
+ set(swig_extra_flags ${swig_extra_flags} ${SWIG_MODULE_${name}_EXTRA_FLAGS})
+ endif()
+ add_custom_command(
+ OUTPUT "${swig_generated_file_fullname}" ${swig_extra_generated_files}
+ # Let's create the ${swig_outdir} at execution time, in case dir contains $(OutDir)
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${swig_outdir}
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${swig_generated_file_path}"
+ COMMAND "${SWIG_EXECUTABLE}"
+ ARGS "-${SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG}"
+ ${swig_source_file_flags}
+ ${CMAKE_SWIG_FLAGS}
+ -outdir ${swig_outdir}
+ ${swig_special_flags}
+ ${swig_extra_flags}
+ ${swig_include_dirs}
+ -o "${swig_generated_file_fullname}"
+ "${swig_source_file_fullname}"
+ MAIN_DEPENDENCY "${swig_source_file_fullname}"
+ DEPENDS ${SWIG_MODULE_${name}_EXTRA_DEPS}
+ COMMENT "Swig source")
+ set_source_files_properties("${swig_generated_file_fullname}" ${swig_extra_generated_files}
+ PROPERTIES GENERATED 1)
+ set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files})
+endmacro()
+
+#
+# Create Swig module
+#
+macro(SWIG_ADD_MODULE name language)
+ SWIG_MODULE_INITIALIZE(${name} ${language})
+ set(swig_dot_i_sources)
+ set(swig_other_sources)
+ foreach(it ${ARGN})
+ if(${it} MATCHES ".*\\.i$")
+ set(swig_dot_i_sources ${swig_dot_i_sources} "${it}")
+ else()
+ set(swig_other_sources ${swig_other_sources} "${it}")
+ endif()
+ endforeach()
+
+ set(swig_generated_sources)
+ foreach(it ${swig_dot_i_sources})
+ SWIG_ADD_SOURCE_TO_MODULE(${name} swig_generated_source ${it})
+ set(swig_generated_sources ${swig_generated_sources} "${swig_generated_source}")
+ endforeach()
+ get_directory_property(swig_extra_clean_files ADDITIONAL_MAKE_CLEAN_FILES)
+ set_directory_properties(PROPERTIES
+ ADDITIONAL_MAKE_CLEAN_FILES "${swig_extra_clean_files};${swig_generated_sources}")
+ add_library(${SWIG_MODULE_${name}_REAL_NAME}
+ MODULE
+ ${swig_generated_sources}
+ ${swig_other_sources})
+ string(TOLOWER "${language}" swig_lowercase_language)
+ if ("${swig_lowercase_language}" STREQUAL "java")
+ if (APPLE)
+ # In java you want:
+ # System.loadLibrary("LIBRARY");
+ # then JNI will look for a library whose name is platform dependent, namely
+ # MacOS : libLIBRARY.jnilib
+ # Windows: LIBRARY.dll
+ # Linux : libLIBRARY.so
+ set_target_properties (${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".jnilib")
+ endif ()
+ endif ()
+ if ("${swig_lowercase_language}" STREQUAL "python")
+ # this is only needed for the python case where a _modulename.so is generated
+ set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES PREFIX "")
+ # Python extension modules on Windows must have the extension ".pyd"
+ # instead of ".dll" as of Python 2.5. Older python versions do support
+ # this suffix.
+ # http://docs.python.org/whatsnew/ports.html#SECTION0001510000000000000000
+ # <quote>
+ # Windows: .dll is no longer supported as a filename extension for extension modules.
+ # .pyd is now the only filename extension that will be searched for.
+ # </quote>
+ if(WIN32 AND NOT CYGWIN)
+ set_target_properties(${SWIG_MODULE_${name}_REAL_NAME} PROPERTIES SUFFIX ".pyd")
+ endif()
+ endif ()
+endmacro()
+
+#
+# Like TARGET_LINK_LIBRARIES but for swig modules
+#
+macro(SWIG_LINK_LIBRARIES name)
+ if(SWIG_MODULE_${name}_REAL_NAME)
+ target_link_libraries(${SWIG_MODULE_${name}_REAL_NAME} ${ARGN})
+ else()
+ message(SEND_ERROR "Cannot find Swig library \"${name}\".")
+ endif()
+endmacro()
+
--- /dev/null
+# - Try to find Glib and its components (gio, gobject etc)
+# Once done, this will define
+#
+# GLIB_FOUND - system has Glib
+# GLIB_INCLUDE_DIRS - the Glib include directories
+# GLIB_LIBRARIES - link these to use Glib
+#
+# Optionally, the COMPONENTS keyword can be passed to find_package()
+# and Glib components can be looked for. Currently, the following
+# components can be used, and they define the following variables if
+# found:
+#
+# gio: GLIB_GIO_LIBRARIES
+# gobject: GLIB_GOBJECT_LIBRARIES
+# gmodule: GLIB_GMODULE_LIBRARIES
+# gthread: GLIB_GTHREAD_LIBRARIES
+#
+# Note that the respective _INCLUDE_DIR variables are not set, since
+# all headers are in the same directory as GLIB_INCLUDE_DIRS.
+#
+# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
+#
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS 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 ITS
+# 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.
+
+find_package(PkgConfig)
+pkg_check_modules(PC_GLIB QUIET glib-2.0)
+
+find_library(GLIB_LIBRARIES
+ NAMES glib-2.0
+ HINTS ${PC_GLIB_LIBDIR}
+ ${PC_GLIB_LIBRARY_DIRS}
+)
+
+# Files in glib's main include path may include glibconfig.h, which,
+# for some odd reason, is normally in $LIBDIR/glib-2.0/include.
+get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH)
+find_path(GLIBCONFIG_INCLUDE_DIR
+ NAMES glibconfig.h
+ HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR}
+ ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS}
+ PATH_SUFFIXES glib-2.0/include
+)
+
+find_path(GLIB_INCLUDE_DIR
+ NAMES glib.h
+ HINTS ${PC_GLIB_INCLUDEDIR}
+ ${PC_GLIB_INCLUDE_DIRS}
+ PATH_SUFFIXES glib-2.0
+)
+
+set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR})
+
+# Version detection
+file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS)
+string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
+set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}")
+set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}")
+
+# Additional Glib components. We only look for libraries, as not all of them
+# have corresponding headers and all headers are installed alongside the main
+# glib ones.
+SET(GLIB_FIND_COMPONENTS gobject; gio; gio-unix;)
+foreach (_component ${GLIB_FIND_COMPONENTS})
+ if (${_component} STREQUAL "gio")
+ find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+ set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES)
+ elseif (${_component} STREQUAL "gobject")
+ find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+ set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES)
+ elseif (${_component} STREQUAL "gmodule")
+ find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+ set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES)
+ elseif (${_component} STREQUAL "gthread")
+ find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR})
+ set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES)
+ elseif (${_component} STREQUAL "gio-unix")
+ # gio-unix is compiled as part of the gio library, but the include paths
+ # are separate from the shared glib ones. Since this is currently only used
+ # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config.
+ pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0)
+ include_directories(${GIO_UNIX_INCLUDE_DIRS})
+ endif ()
+endforeach ()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS}
+ VERSION_VAR GLIB_VERSION)
+
+mark_as_advanced(
+ GLIBCONFIG_INCLUDE_DIR
+ GLIB_GIO_LIBRARIES
+ GLIB_GIO_UNIX_LIBRARIES
+ GLIB_GMODULE_LIBRARIES
+ GLIB_GOBJECT_LIBRARIES
+ GLIB_GTHREAD_LIBRARIES
+ GLIB_INCLUDE_DIR
+ GLIB_INCLUDE_DIRS
+ GLIB_LIBRARIES
+)
+
--- /dev/null
+#.rst:
+# FindGtkDoc
+# ----------
+#
+# CMake macros to find and use the GtkDoc documentation system
+
+# Output variables:
+#
+# GTKDOC_FOUND ... set to 1 if GtkDoc was foung
+#
+# If GTKDOC_FOUND == 1:
+#
+# GTKDOC_SCAN_EXE ... the location of the gtkdoc-scan executable
+# GTKDOC_SCANGOBJ_EXE ... the location of the gtkdoc-scangobj executable
+# GTKDOC_MKDB_EXE ... the location of the gtkdoc-mkdb executable
+# GTKDOC_MKHTML_EXE ... the location of the gtkdoc-mkhtml executable
+# GTKDOC_FIXXREF_EXE ... the location of the gtkdoc-fixxref executable
+
+#=============================================================================
+# Copyright 2009 Rich Wareham
+# Copyright 2015 Lautsprecher Teufel GmbH
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+include(CMakeParseArguments)
+include(FindPackageHandleStandardArgs)
+
+find_package(PkgConfig REQUIRED)
+
+# The UseGtkDoc.cmake module requires at least 1.9, because it doesn't use
+# the deprecated `gtkdoc-mktmpl` tool. We will check if the version satisfies
+# the user's specified dependencies later (with the
+# find_package_handle_standard_args() command).
+pkg_check_modules(GtkDoc REQUIRED gtk-doc>=1.9)
+
+find_program(GTKDOC_SCAN_EXE gtkdoc-scan PATH "${GLIB_PREFIX}/bin")
+find_program(GTKDOC_SCANGOBJ_EXE gtkdoc-scangobj PATH "${GLIB_PREFIX}/bin")
+
+get_filename_component(_this_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
+find_file(GTKDOC_SCANGOBJ_WRAPPER GtkDocScanGObjWrapper.cmake PATH ${_this_dir})
+
+find_program(GTKDOC_MKDB_EXE gtkdoc-mkdb PATH "${GLIB_PREFIX}/bin")
+find_program(GTKDOC_MKHTML_EXE gtkdoc-mkhtml PATH "${GLIB_PREFIX}/bin")
+find_program(GTKDOC_FIXXREF_EXE gtkdoc-fixxref PATH "${GLIB_PREFIX}/bin")
+
+find_package_handle_standard_args(GtkDoc
+ REQUIRED_VARS GTKDOC_SCAN_EXE GTKDOC_SCANGOBJ_EXE GTKDOC_SCANGOBJ_WRAPPER GTKDOC_MKDB_EXE GTKDOC_MKHTML_EXE GTKDOC_FIXXREF_EXE
+ VERSION_VAR GtkDoc_VERSION)
+
+# ::
+#
+# gtk_doc_add_module(doc_prefix sourcedir
+# [XML xmlfile]
+# [FIXXREFOPTS fixxrefoption1...]
+# [IGNOREHEADERS header1...]
+# [DEPENDS depend1...] )
+#
+# sourcedir must be the *full* path to the source directory.
+#
+# If omitted, sgmlfile defaults to the auto generated ${doc_prefix}/${doc_prefix}-docs.xml.
+macro(gtk_doc_add_module _doc_prefix _doc_sourcedir)
+ set(_one_value_args "XML")
+ set(_multi_value_args "DEPENDS" "XML" "FIXXREFOPTS" "IGNOREHEADERS"
+ "CFLAGS" "LDFLAGS" "LDPATH" "SUFFIXES")
+ cmake_parse_arguments("GTK_DOC" "" "${_one_value_args}" "${_multi_value_args}" ${ARGN})
+
+ set(_depends ${GTK_DOC_DEPENDS})
+ set(_xml ${GTK_DOC_XML})
+ set(_fixxrefopts ${GTK_DOC_FIXXREFOPTS})
+ set(_ignoreheaders ${GTK_DOC_IGNOREHEADERS})
+ set(_extra_cflags ${GTK_DOC_CFLAGS})
+ set(_extra_ldflags ${GTK_DOC_LDFLAGS})
+ set(_extra_ldpath ${GTK_DOC_LDPATH})
+ set(_suffixes ${GTK_DOC_SUFFIXES})
+
+ list(LENGTH _xml_file _xml_file_length)
+
+ if(_suffixes)
+ set(_doc_source_suffixes "")
+ foreach(_suffix ${_suffixes})
+ if(_doc_source_suffixes)
+ set(_doc_source_suffixes "${_doc_source_suffixes},${_suffix}")
+ else(_doc_source_suffixes)
+ set(_doc_source_suffixes "${_suffix}")
+ endif(_doc_source_suffixes)
+ endforeach(_suffix)
+ else(_suffixes)
+ set(_doc_source_suffixes "h")
+ endif(_suffixes)
+
+ # set(_do_all ALL)
+
+ set(_opts_valid 1)
+ if(NOT _xml_file_length LESS 2)
+ message(SEND_ERROR "Must have at most one sgml file specified.")
+ set(_opts_valid 0)
+ endif(NOT _xml_file_length LESS 2)
+
+ if(_opts_valid)
+ # a directory to store output.
+ set(_output_dir "${CMAKE_CURRENT_BINARY_DIR}/${_doc_prefix}")
+ set(_output_dir_stamp "${_output_dir}/dir.stamp")
+
+ # set default sgml file if not specified
+ set(_default_xml_file "${_output_dir}/${_doc_prefix}-docs.xml")
+ get_filename_component(_default_xml_file ${_default_xml_file} ABSOLUTE)
+
+ # a directory to store html output.
+ set(_output_html_dir "${_output_dir}/html")
+ set(_output_html_dir_stamp "${_output_dir}/html_dir.stamp")
+
+ # The output files
+ set(_output_decl_list "${_output_dir}/${_doc_prefix}-decl-list.txt")
+ set(_output_decl "${_output_dir}/${_doc_prefix}-decl.txt")
+ set(_output_overrides "${_output_dir}/${_doc_prefix}-overrides.txt")
+ set(_output_sections "${_output_dir}/${_doc_prefix}-sections.txt")
+ set(_output_types "${_output_dir}/${_doc_prefix}.types")
+
+ set(_output_signals "${_output_dir}/${_doc_prefix}.signals")
+
+ set(_output_unused "${_output_dir}/${_doc_prefix}-unused.txt")
+ set(_output_undeclared "${_output_dir}/${_doc_prefix}-undeclared.txt")
+ set(_output_undocumented "${_output_dir}/${_doc_prefix}-undocumented.txt")
+
+ set(_output_xml_dir "${_output_dir}/xml")
+ set(_output_sgml_stamp "${_output_dir}/sgml.stamp")
+
+ set(_output_html_stamp "${_output_dir}/html.stamp")
+
+ # add a command to create output directory
+ add_custom_command(
+ OUTPUT "${_output_dir_stamp}" "${_output_dir}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_dir}"
+ COMMAND ${CMAKE_COMMAND} -E touch ${_output_dir_stamp}
+ VERBATIM)
+
+ set(_ignore_headers_opt "")
+ if(_ignore_headers)
+ set(_ignore_headers_opt "--ignore-headers=")
+ foreach(_header ${_ignore_headers})
+ set(_ignore_headers_opt "${_ignore_headers_opt}${_header} ")
+ endforeach(_header ${_ignore_headers})
+ endif(_ignore_headers)
+
+ # add a command to scan the input
+ add_custom_command(
+ OUTPUT
+ "${_output_decl_list}"
+ "${_output_decl}"
+ "${_output_decl}.bak"
+ "${_output_overrides}"
+ "${_output_sections}"
+ "${_output_types}"
+ "${_output_types}.bak"
+ DEPENDS
+ "${_output_dir}"
+ ${_depends}
+ COMMAND ${GTKDOC_SCAN_EXE}
+ "--module=${_doc_prefix}"
+ "${_ignore_headers_opt}"
+ "--rebuild-sections"
+ "--rebuild-types"
+ "--source-dir=${_doc_sourcedir}"
+ WORKING_DIRECTORY "${_output_dir}"
+ VERBATIM)
+
+ # add a command to scan the input via gtkdoc-scangobj
+ # This is such a disgusting hack!
+ add_custom_command(
+ OUTPUT
+ "${_output_signals}"
+ DEPENDS
+ "${_output_types}"
+ COMMAND ${CMAKE_COMMAND}
+ -D "GTKDOC_SCANGOBJ_EXE:STRING=${GTKDOC_SCANGOBJ_EXE}"
+ -D "doc_prefix:STRING=${_doc_prefix}"
+ -D "output_types:STRING=${_output_types}"
+ -D "output_dir:STRING=${_output_dir}"
+ -D "EXTRA_CFLAGS:STRING=${_extra_cflags}"
+ -D "EXTRA_LDFLAGS:STRING=${_extra_ldflags}"
+ -D "EXTRA_LDPATH:STRING=${_extra_ldpath}"
+ -P ${GTKDOC_SCANGOBJ_WRAPPER}
+ WORKING_DIRECTORY "${_output_dir}"
+ VERBATIM)
+
+ set(_copy_xml_if_needed "")
+ if(_xml_file)
+ get_filename_component(_xml_file ${_xml_file} ABSOLUTE)
+ set(_copy_xml_if_needed
+ COMMAND ${CMAKE_COMMAND} -E copy "${_xml_file}" "${_default_xml_file}")
+ endif(_xml_file)
+
+ set(_remove_xml_if_needed "")
+ if(_xml_file)
+ set(_remove_xml_if_needed
+ COMMAND ${CMAKE_COMMAND} -E remove ${_default_xml_file})
+ endif(_xml_file)
+
+ # add a command to make the database
+ add_custom_command(
+ OUTPUT
+ "${_output_sgml_stamp}"
+ "${_default_xml_file}"
+ DEPENDS
+ "${_output_types}"
+ "${_output_signals}"
+ "${_output_sections}"
+ "${_output_overrides}"
+ ${_depends}
+ ${_remove_xml_if_needed}
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${_output_xml_dir}
+ COMMAND ${GTKDOC_MKDB_EXE}
+ "--module=${_doc_prefix}"
+ "--source-dir=${_doc_sourcedir}"
+ "--source-suffixes=${_doc_source_suffixes}"
+ "--output-format=xml"
+ "--main-sgml-file=${_default_xml_file}"
+ ${_copy_xml_if_needed}
+ WORKING_DIRECTORY "${_output_dir}"
+ VERBATIM)
+
+ # add a command to create html directory
+ add_custom_command(
+ OUTPUT "${_output_html_dir_stamp}" "${_output_html_dir}"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_output_html_dir}
+ COMMAND ${CMAKE_COMMAND} -E touch ${_output_html_dir_stamp}
+ VERBATIM)
+
+ # add a command to output HTML
+ add_custom_command(
+ OUTPUT
+ "${_output_html_stamp}"
+ DEPENDS
+ "${_output_html_dir_stamp}"
+ "${_output_sgml_stamp}"
+ "${_xml_file}"
+ ${_depends}
+ ${_copy_xml_if_needed}
+ COMMAND
+ cd "${_output_html_dir}" && ${GTKDOC_MKHTML_EXE}
+ "${_doc_prefix}"
+ "${_default_xml_file}"
+ COMMAND
+ cd "${_output_dir}" && ${GTKDOC_FIXXREF_EXE}
+ "--module=${_doc_prefix}"
+ "--module-dir=${_output_html_dir}"
+ ${_fixxref_opts}
+ ${_remove_xml_if_needed}
+ VERBATIM)
+
+ add_custom_target(doc-${_doc_prefix} ${_do_all}
+ DEPENDS "${_output_html_stamp}")
+ endif(_opts_valid)
+endmacro(gtk_doc_add_module)
--- /dev/null
+EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "
+from sys import stdout
+from sysconfig import get_path
+path=get_path(name='platlib', vars={'platbase':'${CMAKE_INSTALL_PREFIX}'})
+stdout.write(path)"
+OUTPUT_VARIABLE PYTHON_INSTALL_DIR)
--- /dev/null
+if(NOT APPLE)
+ # We use pkg-config to fing glib et al
+ find_package(PkgConfig)
+ # Find glib et al
+ pkg_check_modules(GLIB REQUIRED glib-2.0 gobject-2.0)
+
+foreach(_flag ${EXTRA_CFLAGS} ${GLIB_CFLAGS})
+ set(ENV{CFLAGS} "$ENV{CFLAGS} \"${_flag}\"")
+endforeach(_flag)
+
+foreach(_flag ${EXTRA_LDFLAGS} ${GLIB_LDFLAGS})
+ set(ENV{LDFLAGS} "$ENV{LDFLAGS} \"${_flag}\"")
+endforeach(_flag)
+
+foreach(_flag ${EXTRA_LDPATH})
+ if(ENV{LD_LIBRARY_PATH})
+ set(ENV{LD_LIBRARY_PATH} "$ENV{LD_LIBRARY_PATH}:\"${_flag}\"")
+ else(ENV{LD_LIBRARY_PATH})
+ set(ENV{LD_LIBRARY_PATH} "${_flag}")
+ endif(ENV{LD_LIBRARY_PATH})
+endforeach(_flag)
+
+message(STATUS "Executing gtkdoc-scangobj with:")
+message(STATUS " CFLAGS: $ENV{CFLAGS}")
+message(STATUS " LDFLAGS: $ENV{LDFLAGS}")
+message(STATUS " LDPATH: $ENV{LD_LIBRARY_PATH}")
+
+execute_process(COMMAND ${GTKDOC_SCANGOBJ_EXE}
+ "--module=${doc_prefix}"
+ "--types=${output_types}"
+ "--output-dir=${output_dir}"
+ WORKING_DIRECTORY "${output_dir}"
+ RESULT_VARIABLE _scan_result)
+
+if(_scan_result EQUAL 0)
+ message(STATUS "Scan succeeded.")
+else(_scan_result EQUAL 0)
+ message(SEND_ERROR "Scan failed.")
+endif(_scan_result EQUAL 0)
+
+endif(NOT APPLE)
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: perl
+ stream: 5.23
+ version: 1
+ context: aa
+ arch: x86_64
+ summary: Perl
+ description: Perl
+ license:
+ module:
+ - MIT
+ profiles:
+ default:
+ rpms: ["test-perl"]
+ artifacts:
+ rpms: ["test-perl-0:5.24-1.module_el8+5182+8241aed2.x86_64"]
+...
+---
+document: modulemd
+version: 2
+data:
+ name: perl-DBI
+ stream: master
+ version: 2
+ context: 2b
+ arch: x86_64
+ summary: Perl-DBI
+ description: Perl-DBI
+ license:
+ module:
+ - MIT
+ dependencies:
+ - requires:
+ perl: ["5.23"]
+ profiles:
+ default:
+ rpms: ["test-perl-DBI"]
+ artifacts:
+ rpms: ["test-perl-DBI-0:1-2.module_el8+6587+9879afr5.x86_64"]
+...
+---
+document: modulemd
+version: 2
+data:
+ name: perl-DBI
+ stream: master
+ version: 2
+ context: 2c
+ arch: x86_64
+ summary: Perl-DBI
+ description: Perl-DBI
+ license:
+ module:
+ - MIT
+ dependencies:
+ - requires:
+ perl: ["5.23"]
+ profiles:
+ default:
+ rpms: ["test-perl-DBI"]
+ artifacts:
+ rpms: ["test-perl-DBI-0:1-2.module_el8+6745+9879ate3.x86_64"]
+...
--- /dev/null
+#! /bin/bash
+
+THISDIR=$(readlink -f $(dirname $0))
+cd $THISDIR
+createrepo_c --no-database --simple-md-filenames .
+modifyrepo_c ./updateinfo.xml repodata --simple-md-filenames
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1621268151</revision>
+ <data type="primary">
+ <checksum type="sha256">85618a80c1345a3010253df7257766980209f86697d979bfe18ea11707a6047d</checksum>
+ <open-checksum type="sha256">167f862cc208d46dd58b2702c86abad087383c03c3030ed714c7baeff2d00cca</open-checksum>
+ <location href="repodata/primary.xml.gz"/>
+ <timestamp>1621268151</timestamp>
+ <size>744</size>
+ <open-size>2665</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">efbf7f021163a3c7698a257351e327102c60bb39a7bdceee77c421f064205e99</checksum>
+ <open-checksum type="sha256">ca5620e2734574d04d3c01ae5a72f865313369954698d71776076b9cbd831bbd</open-checksum>
+ <location href="repodata/filelists.xml.gz"/>
+ <timestamp>1621268151</timestamp>
+ <size>311</size>
+ <open-size>511</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">6673953e1f28f55b9d4c3f38a9e3c0e0ff88ad06fb693b7f15eb241a81b80d71</checksum>
+ <open-checksum type="sha256">0997c242bf1b96372d7a625a73de23dced68cae9375baff0c73215a07693b3f4</open-checksum>
+ <location href="repodata/other.xml.gz"/>
+ <timestamp>1621268151</timestamp>
+ <size>310</size>
+ <open-size>507</open-size>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">20062f5451a8da7a8951336f119f6a8f7411286849b53dc8a179c75270b73216</checksum>
+ <open-checksum type="sha256">6a10d0c26f84f5f74d9ecc379016dd9ed9b9d173a4db17f6dc90665d8563fdea</open-checksum>
+ <location href="repodata/modules.yaml.gz"/>
+ <timestamp>1621268151</timestamp>
+ <size>331</size>
+ <open-size>1117</open-size>
+ </data>
+ <data type="updateinfo">
+ <checksum type="sha256">9d791d16c2adc2d7d4c85b45f2a704edac62a926b09fc20df73207f4190acd49</checksum>
+ <open-checksum type="sha256">3cf7df860860ac7a4a8e64a1a2d71c1ec43225dacbfe09a0cff80f28be3825da</open-checksum>
+ <location href="repodata/updateinfo.xml.gz"/>
+ <timestamp>1621268151</timestamp>
+ <size>708</size>
+ <open-size>2414</open-size>
+ </data>
+</repomd>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<updates>
+ <update from="secresponseteam@foo.bar" status="final" type="enhancement" version="3">
+ <id>FEDORA-2019-0329090518</id>
+ <title>glibc bug fix</title>
+ <issued date="2019-03-29 00:00:00"/>
+ <updated date="2019-03-29 00:00:00"/>
+ <severity>none</severity>
+ <rights>Everyone has them</rights>
+ <summary>summary_1</summary>
+ <description>Enhance some stuff</description>
+ <references>
+ <reference href="https://foobar/foobarupdate_2" id="2222" type="bugzilla" title="222"/>
+ <reference href="https://foobar/foobarupdate_2" id="2222" type="cve" title="CVE-2999"/>
+ </references>
+ <pkglist>
+ <collection short="named collection">
+ <name>Foo component</name>
+ <module name="perl-DBI" stream="master" version="2" context="2c" arch="x86_64"/>
+ <module name="non" stream="existing" version="2" context="module" arch="x86_64"/>
+ <package name="test-perl-DBI" version="1" release="2.module_el8+6745+9879ate3" epoch="0" arch="x86_64" src="http://www.foo.org">
+ <filename>perl-DBI-1-2.module_el8+6745+9879ate3.spec</filename>
+ <reboot_suggested/>
+ </package>
+ <package name="test-perl-DBI-new-collection-override" version="1" release="2.module_el8+6745+9879ate3" epoch="0" arch="x86_64" src="http://www.foo.org">
+ <filename>perl-DBI-1-2.module_el8+6745+9879ate3.spec</filename>
+ <reboot_suggested/>
+ </package>
+ </collection>
+ <collection short="unreal collection">
+ <name>Foo component</name>
+ <module name="perl-DBI" stream="master" version="2" context="2b" arch="x86_64"/>
+ <package name="test-perl-DBI" version="1" release="2.module_el8+6587+9879afr5" epoch="0" arch="x86_64" src="http://www.foo.org">
+ <filename>perl-DBI-1-2.module_el8+6587+9879afr5.spec</filename>
+ <reboot_suggested/>
+ </package>
+ </collection>
+ <collection short="perl collection">
+ <name>perl component</name>
+ <module name="perl" stream="5.23" version="2" context="aa" arch="x86_64"/>
+ <package name="not-present" version="5.24" release="1.module_el8+5182+8241aed2" epoch="0" arch="x86_64" src="http://www.foo.org">
+ <filename>not-present-0:5.24-1.module_el8+5182+8241aed2.x86_64</filename>
+ </package>
+ </collection>
+ </pkglist>
+ </update>
+</updates>
--- /dev/null
+[fedora]
+name=Fedora $releasever - $basearch
+enabled=1
+skip_if_unavailable=False
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1257930816</revision>
+ <data type="primary_db">
+ <location href="repodata/primary.sqlite.bz2"/>
+ <checksum type="sha256">3b7612fe14a6fbc06e3484e738edd08ca30ac14c2d86ea72feef8a39cfee757a</checksum>
+ <timestamp>1257935775.0</timestamp>
+ <size>10126790</size>
+ <open-size>43433984</open-size>
+ <open-checksum type="sha256">4981bf8b555f84f392455b5e91f09954b9f9e187f43c33921bce9cd911917210</open-checksum>
+ <database_version>10</database_version>
+ </data>
+</repomd>
--- /dev/null
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAABAgAGBQJUkVGrAAoJEBlInYFFo37eu14IAKKp2gflZ6osXXCPOmAKm/CM
+6wWMzYyoijCre4D/hbreZu9CyKYYZdoDAhhPW9Laul6fTh8Ijt8zYD9//RkhJ7+3
+fG9dvuxuZF0FjrnFlYZE5oLMl8GuKBTKPY9j3tRvBwHpfLA5vFkQ52cm/n8Sw7qy
+DGSLQJao1Rhwl0B91S8X5WaQtS0CQki8lSjkU7A5glAkH6h6+jNti0Rsoh0Vpkqs
+reFrTs5FtDqP22sx4JMX1VbPjVi4/fL4+WsGMKzWH+t6R8PPCAHZJ2iECA9RqaNr
+R9MIsVXsYP39nJaXrtObDvZARpkaMntPFZuSLJfEH9a1J/eJMhntsm+sjbjwBMA=
+=i6rv
+-----END PGP SIGNATURE-----
--- /dev/null
+gpg --homedir ../../gpgkey/ --armor --detach-sig repomd.xml
--- /dev/null
+[gpg-repo-asc]
+name=Repo GPG checking enabled and .asc file correct in repo
+baseurl=file://$testdatadir/gpg-asc/
+enabled=1
+repo_gpgcheck=1
+gpgkey=file://$testdatadir/gpgkey/signing_key.pub
--- /dev/null
+../../gpg-asc/repodata/repomd.xml
\ No newline at end of file
--- /dev/null
+[gpg-repo-no-asc]
+name=Repo GPG checking enabled but no .asc file present in repo
+baseurl=file://$testdatadir/gpg-no-asc/
+enabled=1
+repo_gpgcheck=1
+gpgkey=file://$testdatadir/gpgkey/signing_key.pub
--- /dev/null
+[gpg-repo-no-pubkey]
+name=Repo GPG checking but no GPG Key set
+baseurl=http://www.dave.org
+enabled=1
+repo_gpgcheck=1
--- /dev/null
+../../gpg-asc/repodata/repomd.xml
\ No newline at end of file
--- /dev/null
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1257930816</revision>
+ <data type="primary_db">
+ <location href="repodata/primary.sqlite.bz2"/>
+ <checksum type="sha256">3b7612fe14a6fbc06e3484e738edd08ca30ac14c2d86ea72feef8a39cfee757a</checksum>
+ <timestamp>1257935775.0</timestamp>
+ <size>10126790</size>
+ <open-size>43433984</open-size>
+ <open-checksum type="sha256">4981bf8b555f84f392455b5e91f09954b9f9e187f43c33921bce9cd911917210</open-checksum>
+ <database_version>10</database_version>
+ </data>
+</repomd>
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAEBAgAGBQJUkFINAAoJEBesuo36lw4X5TgIAKNxupNcO97DCe39vqrVJWNs
+VT4WICPpye3R7hla2vtyB6L5WkK6K0ErcGyoeI3IqC91dAZ7dh1MJ3eLdAIlcPXa
+TGWgPyXAs/V6NlA7bccZawO1spsjIf1HsFDAvB/gPnU5leETpDajlmRlbn6zE4oh
+2iW1BdZzHgizbIuVShR8fylk/xSbMn98WQ9IPPSmLIfec0Fk46UpryOpqamHtsTh
+qr7+4jlVsSWvIsJFGKMrLCeH2Gl6rcGlTs5tAbhymyUXRT0ilWJmJR5t9cphKzO9
+qm+4B1sz55gQ5WlX6/suIfyFCeoFdFrP0lN+uNyJT17u3eZVzkcdx90NHbf7ypU=
+=0OA5
+-----END PGP SIGNATURE-----
--- /dev/null
+[gpg-repo-wrong-asc]
+name=Repo GPG checking enabled but no .asc signed using the wrong key
+baseurl=file://$testdatadir/gpg-wrong-asc/
+enabled=1
+repo_gpgcheck=1
+gpgkey=file://$testdatadir/gpgkey/signing_key.pub
--- /dev/null
+*~
+trustdb.gpg
--- /dev/null
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQENBFSQQ9YBCADUzwTzWC+T8m5cync71ZoxXoNnvdhxqpYHbE5+n0WFBQK8c1mz
+HzonBHKKYNdERtb9GM1fY+LxI4jtTK34MvFmtbJDv/zutTgxczHvXr2KT/Ix6Wm+
+FQ+XDJ+9eY7yvAL77YUcHXyV0dDyxOhZBPSn8/7riiKy1nYp7KNHcQa0su4yUP2B
+lRhne/+HLWwPwglSit6FO9BcOKTki0DVzw05KLlBi1CUUrE+Dg6VDu6+9VDUCaPc
+qEuh/AbVOiPT2WGgDulMS997UgyNL60KLzJIzh67+KA5DmbfnJv7ol1WA3yykZq2
+DTNSETY/+1GA6Js6rVWFl7RiQoxImv1NAIAZABEBAAG0IGxpYmhpZiB0ZXN0IGtl
+eSA8dGVzdEBlbWFpbC5jb20+iQE4BBMBAgAiBQJUkEPWAhsDBgsJCAcDAgYVCAIJ
+CgsEFgIDAQIeAQIXgAAKCRAZSJ2BRaN+3jxYB/97pdHNVnWD5vcfcTjE4BydvdH6
+SHY4a42E60grmFp/B3hbUxqWIb/qPFKtO5jPac/AxwU7MLm/NHTOzHp4ubSlmxxH
+DDB643rPRdHT12Icfdqqbd5Ic4/YLsYTP+g8qHtIzKtzfB18R8Kvk+jTMa+06HAX
+5x4CFcTLscZ6oaSOB92aMPk8OuU3aHuIzxgAldt6giVD9LafStld85WaLnOxv37A
+ASu8X+Jsd5FdD+2jWFmsmsG0X2uLAOdR6YKDlNK1lMrGzbUIhnA0SQCI6o8QCkio
+U1Ut6V0gIboVgUYh1+0X/zcJKl4PRXGPOUAAC+AdssDfJvlEC6361GNhHon6uQEN
+BFSQQ9YBCACwPoMoMAEsIFDpmPvikaPfJjvtrOM2Of9Rgh41Rc8Q2oft52Bjjpcf
+ftbrg0Ic+0EcCmeeQhJzAcZ+rv+tf4YuBpu65CQRhzLT9mJofWwEHqK6Ng/9cY/u
+1hAoRkGoojr/a2tR8ZoE3L1bomjXYCEDEYQnThctaYNmuR/9WAXAgdwOZg3YgE8Y
+kioJ8OGv5NJ9q/nWFDdGqmElXQHIJFOROT/SgUfATSwXMhfiTMaoSQDPaiyAz3fz
+P6aeSAahv1EWhk5g74QuUD3TI/AcGwZElWkJv2oTrac6KlHBPPMAYuRoyHkPkRSr
+SX3YWcS62ZPmPpg+Nwrb7rcFQGJ1WdNBABEBAAGJAR8EGAECAAkFAlSQQ9YCGwwA
+CgkQGUidgUWjft66uggAy9eQFjlx3gi0cy3QvKBSBVmmB4dZwI6ZMXLpAr0EG96N
+fWKONkAxCvaMJTDI5YPqckTWsct+m/936tcr455k1kD25d3pSGR4EYzJnKae/+vf
+8WPRcmLchnPniH1OiwimRRY3Hz72qGm4WhPqKx/jw4i7fI8Z6rTCyPPLvBdIn6+P
+Kg0H9QET1gwPMCQm5P8vZz+xap8JG2tQ9C5Q/SDo4nt/NEs3/NjMRHDiIKKFfY+E
+NOBa1dEEc6oBtzWd/YpAWkGyMSdm8ZeCaFjg4tPfI73ny4rPGHQmV2IAW0jz34D5
+wAtzTXosX0dapFxctR30/cj8mvNnQjjzX26kF0wW4g==
+=+Qm5
+-----END PGP PUBLIC KEY BLOCK-----
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: ok 1 0 x86_64
+=Pkg: missing 1 0 x86_64
+=Req: missing-dep
+=Pkg: conflict 1 0 x86_64
+=Con: ok
+=Pkg: dup 1 1 x86_64
+=Pkg: dup 2 1 x86_64
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: k 1 0 x86_64
+=Pkg: k-m 1 0 x86_64
+=Req: k = 1-0
+=Pkg: k-freak-1-0 1 0 x86_64
+=Req: k = 1-0
+=Pkg: k 1 1 x86_64
+=Pkg: k-m 1 1 x86_64
+=Req: k = 1-1
+=Pkg: k 2 0 x86_64
+=Pkg: k-m 2 0 x86_64
+=Req: k = 2-0
+=Pkg: k 3 0 x86_64
+=Pkg: k-m 3 0 x86_64
+=Req: k = 3-0
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: baby 6:5.0 11 x86_64
+=Pkg: dog 1 1 x86_64
+=Con: custard = 1.1
+=Pkg: flying 2 9 noarch
+=Req: P-lib >= 3
+=Pkg: fool 1 3 noarch
+=Prv: fool <= 1-3
+=Prv: /no/answers
+=Pkg: gun 4 1 i686
+=Pkg: jay 5.0 0 x86_64
+=Pkg: jay 6.0 0 x86_64
+=Pkg: pilchard 1.2.3 1 i686
+=Pkg: pilchard 1.2.3 1 x86_64
+=Pkg: penny 4 1 noarch
+=Prv: P = 3-3
+=Sum: in my eyes
+=Pkg: penny-lib 4 1 x86_64
+=Prv: P-lib = 3-3
+=Sum: in my ears
+=Pkg: pigs 4 0 noarch
+=Req: /usr/bin/away
+=Pkg: tour 4 0 noarch
+=Prv: /usr/bin/away
+=Pkg: bloop 1.0 1 noarch
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: flying 3 0 noarch
+=Req: P-lib = 3-4
+=Pkg: penny-lib 4 1 x86_64
+=Vnd: PerfectlyLoud
+=Sum: in my ears
+=Prv: P-lib = 3-4
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: gun 4 1 i686
+=Pkg: gun 2 0 x86_64
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: A 1 0 noarch
+=Req: somereq
+=Pkg: B 1 0 noarch
+=Rec: C
+=Prv: somereq
+=Pkg: C 1 0 noarch
+=Prv: somereq
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: k 3 1 x86_64
+=Pkg: k-m 3 1 x86_64
+=Req: k = 3-1
+=Pkg: k 3 6 x86_64
+=Pkg: k-m 3 6 x86_64
+=Req: k = 3-6
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: baby 6:4.9 3 x86_64
+=Sup: flying
+=Pkg: flying 3 0 noarch
+=Req: P-lib
+=Rec: baby
+=Sug: walrus
+=Pkg: fool 1 3 noarch
+=Prv: fool <= 1-3
+=Pkg: hello 1 1 noarch
+=Req: goodbye
+=Pkg: jay 4.9 0 x86_64
+=Pkg: jay 5.0 0 x86_64
+=Pkg: jay 6.0 0 x86_64
+=Pkg: penny 4 1 noarch
+=Prv: P = 3-3
+=Sum: in my eyes
+=Pkg: penny-lib 4 1 x86_64
+=Prv: P-lib = 3-3
+=Pkg: penny-lib 4 1 i686
+=Prv: P-lib = 3-3
+=Sum: in my ears
+=Pkg: penny-lib-devel 4 1 x86_64
+=Pkg: semolina 2 0 x86_64
+=Pkg: semolina 2 0 i686
+=Pkg: walrus 2 5 noarch
+=Prv: walrus <= 2-5
+=Req: semolina = 2
+=Req: fool
+=Enh: flying
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: custard 1 2 ppc64
+=Pkg: custard 1 3 ppc64
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: dog 1 2 i686
+=Con: custard = 1.2
+=Pkg: dog 1 2 x86_64
+=Con: custard = 1.2
+=Pkg: fool 1 5 noarch
+=Prv: fool <= 1-5
+=Prv: fool-lib = 3.3
+=Obs: penny <= 4-1
+=Obs: baby = 6:4.8-3
+=Pkg: flying 3 0 noarch
+=Req: P-lib
+=Pkg: flying 3.1 0 x86_64
+=Req: P-lib
+=Pkg: flying 3.2 0 noarch
+=Req: P-lib >= 3-4
+=Pkg: pilchard 1.2.4 1 i686
+=Pkg: pilchard 1.2.4 1 x86_64
+=Pkg: pilchard 1.2.4 2 x86_64
+=Pkg: walrus 2 6 noarch
+=Prv: walrus <= 2-5
+=Req: semolina = 2
+=Req: fool
+=Pkg: dodo 1.0 1 noarch
+=Req: dodo-dep
+=Pkg: dodo-dep-a 1.0 1 noarch
+=Prv: dodo-dep
+=Pkg: dodo-dep-b 1.0 1 noarch
+=Prv: dodo-dep
+=Pkg: bloop 1.0 1 noarch
+=Pkg: bloop-ext 1.0 1 noarch
+=Req: bloop = 1.0-1
+=Pkg: bloop 2.0 1 noarch
+=Pkg: bloop-ext 2.0 1 noarch
+=Req: bloop = 2.0-1
--- /dev/null
+=Ver: 2.0
+#
+=Pkg: foolish-grin 1 4 noarch
+=Vnd: PerfectlyLoud
+=Obs: fool = 1-3
+=Prv: fool = 1-3
+=Pkg: gun 5 1 x86_64
--- /dev/null
+Summary: mystery package
+Name: mystery
+Version: 19.67
+Release: 1
+Group: Utilities
+License: GPLv2+
+Distribution: Hawkey test suite.
+BuildArch: noarch
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-hawkey
+
+%description
+Hawkey mystery package to test filelists handling.
+
+%package devel
+Summary: Devel subpackage.
+Group: Development/Libraries
+
+%description devel
+Magical development files for mystery.
+
+%prep
+
+%build
+
+%install
+mkdir -p %{buildroot}/%_bindir
+echo "thats an invitation" > %{buildroot}/%_bindir/my
+echo "make a reservation" > %{buildroot}/%_bindir/ste
+echo "step right this way" > %{buildroot}/%_bindir/ry
+
+%files devel
+%_bindir/my
+%_bindir/ste
+%_bindir/ry
--- /dev/null
+#! /bin/bash
+
+THISDIR=$(readlink -f $(dirname $0))
+cd $THISDIR
+git rm -rf repodata/ drpms/
+createrepo --deltas --oldpackagedirs=../yum_oldrpms/ --no-database --baseurl disagree .
+cp updateinfo.xml.gz repodata/
+pushd repodata/
+sed -i -e '$d' repomd.xml # delete the last line: </repomd>
+cat >>repomd.xml <<EOF
+<data type="updateinfo">
+ <checksum type="sha256">$(sha256sum updateinfo.xml.gz |cut -f 1 -d ' ')</checksum>
+ <location href="repodata/updateinfo.xml.gz"/>
+ <timestamp>1284438472</timestamp>
+</data>
+</repomd>
+EOF
+popd
+
+git add repodata/ drpms/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1404109454</revision>
+<data type="filelists">
+ <checksum type="sha256">4d4b903662ace0b08bda1d53f89c333614b7f658172bc9f0c87b0eef276ff5a1</checksum>
+ <open-checksum type="sha256">1a131db9fa5d60090afe7481a184966187df593a37e0199fd67d9d8c935d980f</open-checksum>
+ <location href="repodata/4d4b903662ace0b08bda1d53f89c333614b7f658172bc9f0c87b0eef276ff5a1-filelists.xml.gz"/>
+ <timestamp>1404109454</timestamp>
+ <size>377</size>
+ <open-size>814</open-size>
+</data>
+<data type="prestodelta">
+ <checksum type="sha256">52d800b3426c540bb88a80d01fb6c8d227ae14edca7446fa0f348a286223fb8b</checksum>
+ <open-checksum type="sha256">668513ac58d09eb8febf3672dc6e3bc9a4df5f25738e6ce62440cc6c6095e032</open-checksum>
+ <location href="repodata/52d800b3426c540bb88a80d01fb6c8d227ae14edca7446fa0f348a286223fb8b-prestodelta.xml.gz"/>
+ <timestamp>1404109454</timestamp>
+ <size>311</size>
+ <open-size>491</open-size>
+</data>
+<data type="other">
+ <checksum type="sha256">51fb8278682bdb0ea0956720b098dadf637efc01566acb48203c54c90ba86dda</checksum>
+ <open-checksum type="sha256">5dc6290ad5d8a2bdef6fcd546b03650f3c1b85d6062a4df01c9f7da8b2947e24</open-checksum>
+ <location href="repodata/51fb8278682bdb0ea0956720b098dadf637efc01566acb48203c54c90ba86dda-other.xml.gz"/>
+ <timestamp>1404109454</timestamp>
+ <size>294</size>
+ <open-size>452</open-size>
+</data>
+<data type="primary">
+ <checksum type="sha256">f1ab2aa6c0e5881b9365f83a951e6696812ebfaaf56fee310c3f080c8849a1b4</checksum>
+ <open-checksum type="sha256">533743dcdacef3afa4581b49a1ce09c196b24872ab3a8ec70f8cd4b2c5cb9b98</open-checksum>
+ <location href="repodata/f1ab2aa6c0e5881b9365f83a951e6696812ebfaaf56fee310c3f080c8849a1b4-primary.xml.gz"/>
+ <timestamp>1404109454</timestamp>
+ <size>869</size>
+ <open-size>2253</open-size>
+</data>
+<data type="updateinfo">
+ <checksum type="sha256">3888e1b46e2cb71d6a85f74d1f6d88652a9e3ed2bb85b30ae592aa0c0de91627</checksum>
+ <location href="repodata/updateinfo.xml.gz"/>
+ <timestamp>1284438472</timestamp>
+</data>
+</repomd>
--- /dev/null
+Summary: tour package
+Name: tour
+Version: 4
+Release: 6
+Group: Utilities
+License: GPLv2+
+Distribution: Hawkey test suite.
+BuildArch: noarch
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-hawkey
+Packager: roll up <roll@up.net>
+%global __requires_exclude_from ^%{python_sitelib}/.*$
+
+%description
+Hawkey tour package to test filelists handling.
+
+%prep
+
+%build
+
+%install
+mkdir -p %{buildroot}/%_sysconfdir
+mkdir -p %{buildroot}/%_bindir
+mkdir -p %{buildroot}/%python_sitelib/tour
+echo "roll up" > %{buildroot}/%_sysconfdir/rollup
+echo "dying to" > %{buildroot}/%_sysconfdir/takeyouaway
+echo "take you away" > %{buildroot}/%_bindir/away
+echo "take = 3" > %{buildroot}/%python_sitelib/tour/today.py
+
+%files
+%_sysconfdir/rollup
+%_sysconfdir/takeyouaway
+%_bindir/away
+%python_sitelib/tour/today.py*
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+[main]
+gpgcheck=0
+installonly_limit=3
+clean_requirements_on_remove=True
+install_weak_deps=0
+modulesdir=etc/dnf/modules.d
+reposdir=/home/mhatina/share/dnf/tests/modules/etc/dnf/repos.d
+moduledefaultsdir=/home/mhatina/share/dnf/tests/modules/etc/dnf/modules.defaults.d
--- /dev/null
+[main]
+gpgcheck=0
+installonly_limit=3
+clean_requirements_on_remove=True
+install_weak_deps=0
+modulesdir=etc/dnf/modules.d
+reposdir=@CMAKE_CURRENT_SOURCE_DIR@/tests/modules/etc/dnf/repos.d
+moduledefaultsdir=@CMAKE_CURRENT_SOURCE_DIR@/tests/modules/etc/dnf/modules.defaults.d
--- /dev/null
+[base-runtime]
+stream = f26
+version = 1
+profiles =
+enabled = 1
+locked = 0
\ No newline at end of file
--- /dev/null
+[httpd]
+stream = 2.4
+version = 1
+profiles =
+enabled = 1
+locked = 0
\ No newline at end of file
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: base-runtime
+ stream: f26
+ profiles:
+ f26: [minimal]
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+[boltron]
+name=Boltron
+baseurl=https://download.fedoraproject.org/pub/alt/unofficial/releases/26/Server/$basearch/os/
+enabled=1
+gpgcheck=0
+metadata_expire=0
--- /dev/null
+[copr]
+name=Copr
+baseurl=http://copr-be-dev.cloud.fedoraproject.org/results/frostyx/testmodule/modules/fedora-rawhide-x86_64+httpd-master-20180118000705/latest/x86_64/
+enabled=1
+gpgcheck=0
+metadata_expire=0
--- /dev/null
+[updates-modular]
+name=Fedora Modular $releasever - $basearch - Updates
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/Modular/$basearch/os/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-f$releasever&arch=$basearch
+enabled=1
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+metadata_expire=6h
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[updates-modular-debuginfo]
+name=Fedora Modular $releasever - $basearch - Updates - Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/Modular/$basearch/debug/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-debug-f$releasever&arch=$basearch
+enabled=0
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+metadata_expire=6h
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[updates-modular-source]
+name=Fedora Modular $releasever - Updates Source
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/Modular/source/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-modular-source-f$releasever&arch=$basearch
+enabled=0
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+metadata_expire=6h
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
--- /dev/null
+[fedora-modular]
+name=Fedora Modular $releasever - $basearch
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Modular/$basearch/os/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-$releasever&arch=$basearch
+enabled=1
+#metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[fedora-modular-debuginfo]
+name=Fedora Modular $releasever - $basearch - Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Modular/$basearch/debug/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-debug-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[fedora-modular-source]
+name=Fedora Modular $releasever - Source
+failovermethod=priority#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Modular/source/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-modular-source-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
--- /dev/null
+[fedora]
+name=Fedora $releasever - $basearch
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
+enabled=1
+metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[fedora-debuginfo]
+name=Fedora $releasever - $basearch - Debug
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-debug-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
+
+[fedora-source]
+name=Fedora $releasever - Source
+failovermethod=priority
+#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/source/tree/
+metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-source-$releasever&arch=$basearch
+enabled=0
+metadata_expire=7d
+repo_gpgcheck=0
+type=rpm
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
+skip_if_unavailable=False
--- /dev/null
+[test]
+name=Test
+baseurl=file:///Users/mhatina/Projects/dnf/libdnf/tests/libdnf/data/tests/modules/modules/_all/x86_64/
+enabled=1
+gpgcheck=0
+metadata_expire=0
--- /dev/null
+[test]
+name=Test
+baseurl=file://@CMAKE_CURRENT_SOURCE_DIR@/tests/modules/modules/_all/x86_64/
+enabled=1
+gpgcheck=0
+metadata_expire=0
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.i686
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.i686
+ - filesystem-0:3.2-40.i686
+ - glibc-0:2.25-4.i686
+ - glibc-common-0:2.25-4.i686
+ - glibc-debuginfo-common-0:2.25-4.i686
+ - kernel-0:4.11.0-1.i686
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.i686
+ - systemd-0:233-3.i686
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.i686
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.i686
+ - filesystem-0:3.2-40.i686
+ - glibc-0:2.25.90-2.i686
+ - glibc-common-0:2.25.90-2.i686
+ - glibc-debuginfo-common-0:2.25.90-2.i686
+ - kernel-0:4.11.0-1.i686
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.i686
+ - systemd-0:233-3.i686
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.i686
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.i686
+ - filesystem-0:3.2-21.i686
+ - glibc-0:2.17-157.i686
+ - glibc-common-0:2.17-157.i686
+ - glibc-debuginfo-common-0:2.17-157.i686
+ - kernel-0:3.10.0-514.i686
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.i686
+ - systemd-0:219-30.i686
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.i686
+ - httpd-doc-0:2.2.15-59.i686
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.i686
+ - httpd-doc-0:2.4.25-7.i686
+ - libnghttp2-0:1.21.1-1.i686
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.i686
+ - httpd-doc-0:2.4.25-8.i686
+ - libnghttp2-0:1.21.1-1.i686
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467024</revision>
+ <data type="primary">
+ <checksum type="sha256">27c16fcce1e460811fc9c9edc21d54f52aa75dd49365d66d010ac3fb506803f2</checksum>
+ <open-checksum type="sha256">17acd7a62c4a41041f797ba0b60c8a4bcf9a201b5b055c41d317ac04c4a9ba69</open-checksum>
+ <location href="repodata/27c16fcce1e460811fc9c9edc21d54f52aa75dd49365d66d010ac3fb506803f2-primary.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>4352</size>
+ <open-size>46275</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">2b48025c07f5cfd5170fe7326855d09d65914fc7c14d74998b6226a72451d903</checksum>
+ <open-checksum type="sha256">3342bbb053063797afa5ae4debb735845d30f66675f8ed0c40fee20403a57f8b</open-checksum>
+ <location href="repodata/2b48025c07f5cfd5170fe7326855d09d65914fc7c14d74998b6226a72451d903-filelists.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>2314</size>
+ <open-size>7537</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">006316d6be24801d3eab16966f9054e2676de83dca78f52871d1a15e2b72e79e</checksum>
+ <open-checksum type="sha256">7f99a6075c48030eaeb2da5b94ff7c69d79aef016c1bb404a52078c06bb2c397</open-checksum>
+ <location href="repodata/006316d6be24801d3eab16966f9054e2676de83dca78f52871d1a15e2b72e79e-other.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>2269</size>
+ <open-size>7392</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">6da5c34843c0889b8a035ff92062f197da16a59518c65362e34888f94511f847</checksum>
+ <open-checksum type="sha256">e246bd775c8dd6513b29f7e8137cd0105d47d71b5caa63de5c6dc5d4c8c18f7d</open-checksum>
+ <location href="repodata/6da5c34843c0889b8a035ff92062f197da16a59518c65362e34888f94511f847-primary.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>8475</size>
+ <open-size>122880</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">323709d382b9a9b290d714dab4dab7153aafa895681583c393db1540d0466ed3</checksum>
+ <open-checksum type="sha256">5c79aa0769bcc6deaccc75f0bdd79581c7258103f3a88d7ab5c238f4c7cbd98d</open-checksum>
+ <location href="repodata/323709d382b9a9b290d714dab4dab7153aafa895681583c393db1540d0466ed3-filelists.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>3462</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">6cefdf84131c57f1e0a7e40c3fb025df22e4938e6b690e6c9835f3d89fa67638</checksum>
+ <open-checksum type="sha256">985226a8d5b1ee02b6e06b69ca77f1757d8e28c29ec3dd24580f4bd1a256beb1</open-checksum>
+ <location href="repodata/6cefdf84131c57f1e0a7e40c3fb025df22e4938e6b690e6c9835f3d89fa67638-other.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>3338</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">d50c329d3c3b4f34044ae534725bc06c9ee9f459f27586aacc8f4e8f3331bff1</checksum>
+ <open-checksum type="sha256">4b47c90e488da6226ebcb6937f57f70bff3ca8f00a82a383702b9a8fa812fa78</open-checksum>
+ <location href="repodata/d50c329d3c3b4f34044ae534725bc06c9ee9f459f27586aacc8f4e8f3331bff1-modules.yaml.gz"/>
+ <timestamp>1531828718</timestamp>
+ <size>632</size>
+ <open-size>3977</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.s390x
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.s390x
+ - filesystem-0:3.2-40.s390x
+ - glibc-0:2.25-4.s390x
+ - glibc-common-0:2.25-4.s390x
+ - glibc-debuginfo-common-0:2.25-4.s390x
+ - kernel-0:4.11.0-1.s390x
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.s390x
+ - systemd-0:233-3.s390x
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.s390x
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.s390x
+ - filesystem-0:3.2-40.s390x
+ - glibc-0:2.25.90-2.s390x
+ - glibc-common-0:2.25.90-2.s390x
+ - glibc-debuginfo-common-0:2.25.90-2.s390x
+ - kernel-0:4.11.0-1.s390x
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.s390x
+ - systemd-0:233-3.s390x
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.s390x
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.s390x
+ - filesystem-0:3.2-21.s390x
+ - glibc-0:2.17-157.s390x
+ - glibc-common-0:2.17-157.s390x
+ - glibc-debuginfo-common-0:2.17-157.s390x
+ - kernel-0:3.10.0-514.s390x
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.s390x
+ - systemd-0:219-30.s390x
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.s390x
+ - httpd-doc-0:2.2.15-59.s390x
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.s390x
+ - httpd-doc-0:2.4.25-7.s390x
+ - libnghttp2-0:1.21.1-1.s390x
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.s390x
+ - httpd-doc-0:2.4.25-8.s390x
+ - libnghttp2-0:1.21.1-1.s390x
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467025</revision>
+ <data type="primary">
+ <checksum type="sha256">4a4495b4a9ca8d88506fe8e69d8f78f8ce15fff85185aee7b655e497bc62e04a</checksum>
+ <open-checksum type="sha256">334cb4bd6bd4d573a31a04fc8585098c26c5f8008589639dcc111d1521218fcd</open-checksum>
+ <location href="repodata/4a4495b4a9ca8d88506fe8e69d8f78f8ce15fff85185aee7b655e497bc62e04a-primary.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>4377</size>
+ <open-size>46442</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">d5e48682cd192e754842cb9db90de2a097514f535ea228d9e1dbf9b9b6e24d9d</checksum>
+ <open-checksum type="sha256">194144c44a98933ff564c3d23319c3dca0acf556c689a8e502ff9418099724e6</open-checksum>
+ <location href="repodata/d5e48682cd192e754842cb9db90de2a097514f535ea228d9e1dbf9b9b6e24d9d-filelists.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>2326</size>
+ <open-size>7580</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">e604471cac154e78c098d14de5ba51cf9ad6c10c4187006eeb67b2b2c50a4440</checksum>
+ <open-checksum type="sha256">e904e8ca35ba4071edad77b404d2e8b8830c8d7452975598a2e070eee17afb46</open-checksum>
+ <location href="repodata/e604471cac154e78c098d14de5ba51cf9ad6c10c4187006eeb67b2b2c50a4440-other.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>2280</size>
+ <open-size>7429</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">e86f1444bd807c0d5572e8459a87760babc6f399207f81627a6100a7efd769bc</checksum>
+ <open-checksum type="sha256">90c477a055753cfa1819601887d6e5f754629b2f4771d7e6c6eb0dffc5ac5b4e</open-checksum>
+ <location href="repodata/e86f1444bd807c0d5572e8459a87760babc6f399207f81627a6100a7efd769bc-primary.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>8490</size>
+ <open-size>122880</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">f725aa4c6cc441b905246cbc159bc62e090ce655c65892df6988e4468d155162</checksum>
+ <open-checksum type="sha256">25638cadb9b8f2681a3c1effb436d4f20ee645a4b162a6a3503df3b8178dee0b</open-checksum>
+ <location href="repodata/f725aa4c6cc441b905246cbc159bc62e090ce655c65892df6988e4468d155162-filelists.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>3476</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">9a2de3d81cefc7d5f464f0a6b7494db74f0c65a6b8c62e6c7b084a30532181d4</checksum>
+ <open-checksum type="sha256">ba483e51dc3f3dc9269e4815a830c2c25b6cac8b4590b1466bdd1bfbaab38073</open-checksum>
+ <location href="repodata/9a2de3d81cefc7d5f464f0a6b7494db74f0c65a6b8c62e6c7b084a30532181d4-other.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>3329</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">425cec0f040291008c346d22f9baea2594b5991d9b0f507d6349a6c905b7b82e</checksum>
+ <open-checksum type="sha256">a8239b37c8f33f0850e440e0031c4117e532cb9aea3cb70796080ab1a8f9f80c</open-checksum>
+ <location href="repodata/425cec0f040291008c346d22f9baea2594b5991d9b0f507d6349a6c905b7b82e-modules.yaml.gz"/>
+ <timestamp>1531828718</timestamp>
+ <size>636</size>
+ <open-size>4018</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.x86_64
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.x86_64
+ - filesystem-0:3.2-40.x86_64
+ - glibc-0:2.25-4.x86_64
+ - glibc-common-0:2.25-4.x86_64
+ - glibc-debuginfo-common-0:2.25-4.x86_64
+ - kernel-0:4.11.0-1.x86_64
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.x86_64
+ - systemd-0:233-3.x86_64
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.x86_64
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.x86_64
+ - filesystem-0:3.2-40.x86_64
+ - glibc-0:2.25.90-2.x86_64
+ - glibc-common-0:2.25.90-2.x86_64
+ - glibc-debuginfo-common-0:2.25.90-2.x86_64
+ - kernel-0:4.11.0-1.x86_64
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.x86_64
+ - systemd-0:233-3.x86_64
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.x86_64
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.x86_64
+ - filesystem-0:3.2-21.x86_64
+ - glibc-0:2.17-157.x86_64
+ - glibc-common-0:2.17-157.x86_64
+ - glibc-debuginfo-common-0:2.17-157.x86_64
+ - kernel-0:3.10.0-514.x86_64
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.x86_64
+ - systemd-0:219-30.x86_64
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.x86_64
+ - httpd-doc-0:2.2.15-59.x86_64
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.x86_64
+ - httpd-doc-0:2.4.25-7.x86_64
+ - libnghttp2-0:1.21.1-1.x86_64
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.x86_64
+ - httpd-doc-0:2.4.25-8.x86_64
+ - libnghttp2-0:1.21.1-1.x86_64
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467025</revision>
+ <data type="primary">
+ <checksum type="sha256">7b20d2285e9d41d2f96f67029a28d11249485ad787606017bd855a3263d2209b</checksum>
+ <open-checksum type="sha256">2f9aa5b9644222e2d51c14953d49027543349966552b583281ace7b60f349e66</open-checksum>
+ <location href="repodata/7b20d2285e9d41d2f96f67029a28d11249485ad787606017bd855a3263d2209b-primary.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>4383</size>
+ <open-size>46479</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">fca8343fe9e52b62cbf4b64a0730ffb546bda5542286a884da54c1db5e522943</checksum>
+ <open-checksum type="sha256">43210e3a275ec3f84f30e2138090eabf86258848a09e08be2234eb1e5e02827c</open-checksum>
+ <location href="repodata/fca8343fe9e52b62cbf4b64a0730ffb546bda5542286a884da54c1db5e522943-filelists.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>2319</size>
+ <open-size>7617</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">02dd29c9b3c78f6d04f8853f7833cd63947eb3ef877917ef9a96839889d9f98f</checksum>
+ <open-checksum type="sha256">219765d1a1741fbfc7fbf261632164db29977edc231294e526c472d905cf648d</open-checksum>
+ <location href="repodata/02dd29c9b3c78f6d04f8853f7833cd63947eb3ef877917ef9a96839889d9f98f-other.xml.gz"/>
+ <timestamp>1528467025</timestamp>
+ <size>2276</size>
+ <open-size>7466</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">d36cc059f1588d02469a7259af1a2a3b7764c2c039483b9c2fb8f61ac766ee7c</checksum>
+ <open-checksum type="sha256">082dbb6a0b9389adc836b4c84a06ee4ff5fee642c158f3541c690641d47a99fe</open-checksum>
+ <location href="repodata/d36cc059f1588d02469a7259af1a2a3b7764c2c039483b9c2fb8f61ac766ee7c-primary.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>8510</size>
+ <open-size>122880</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">a523bcf4140225dbb5a17cfc86ad198f02722913f219dd50d29eb6465acf8ca1</checksum>
+ <open-checksum type="sha256">8c3c8ae9109b192c9a4212969cc7bec2cc0d59b8b4ebcd4b71af77eb72e375b7</open-checksum>
+ <location href="repodata/a523bcf4140225dbb5a17cfc86ad198f02722913f219dd50d29eb6465acf8ca1-filelists.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>3446</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">c66ef9ad85b472dd8bfd68105fc5e2669b0ae73f18fd39ae6eb046665857feba</checksum>
+ <open-checksum type="sha256">4a0e87dacee0b20e8dd10c132d7c25d580bbe7c844b02e0ffbc04209fc8af7d4</open-checksum>
+ <location href="repodata/c66ef9ad85b472dd8bfd68105fc5e2669b0ae73f18fd39ae6eb046665857feba-other.sqlite.bz2"/>
+ <timestamp>1528467025</timestamp>
+ <size>3316</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">02517771d46f54572e172605d193e70f158fc88db676cd7d02158736a8f8c7f8</checksum>
+ <open-checksum type="sha256">01eaf5e01c53f7bf36c6654ba6ee9624720edbd0cb32bbd53654464a8be91242</open-checksum>
+ <location href="repodata/02517771d46f54572e172605d193e70f158fc88db676cd7d02158736a8f8c7f8-modules.yaml.gz"/>
+ <timestamp>1531828718</timestamp>
+ <size>638</size>
+ <open-size>4059</open-size>
+ </data>
+</repomd>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467023</revision>
+ <data type="primary">
+ <checksum type="sha256">77cc6a35562eea13f53bf8959047662c3e69b5b8a073a26ef456fb871ce193df</checksum>
+ <open-checksum type="sha256">c89015ed41d05a49cd96f8c919e52abb67b433f8cb45658770e8c1bfca866cdc</open-checksum>
+ <location href="repodata/77cc6a35562eea13f53bf8959047662c3e69b5b8a073a26ef456fb871ce193df-primary.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>1316</size>
+ <open-size>9123</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">3d5f972e2bc031327f700070ea2ecaea8683cab617e076aefca14ba2a498f65b</checksum>
+ <open-checksum type="sha256">05bdcce7262b9a74a5a780d4eb8d97031013da37c01c55a04bc5e9cf95f3e20b</open-checksum>
+ <location href="repodata/3d5f972e2bc031327f700070ea2ecaea8683cab617e076aefca14ba2a498f65b-filelists.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>592</size>
+ <open-size>1525</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">861d4c320499af7bb56d516e6045bd94690fe7227d4734892ad4f8b67223a9f3</checksum>
+ <open-checksum type="sha256">76615058081b8f843daa015082bdb7197118fb5e4a7c12d0ce53b8637eb048f6</open-checksum>
+ <location href="repodata/861d4c320499af7bb56d516e6045bd94690fe7227d4734892ad4f8b67223a9f3-other.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>591</size>
+ <open-size>1521</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">5dfb619f487431ed8697b8351dfc08b8bd1d523a17ea44ce2a19a0a308c04c16</checksum>
+ <open-checksum type="sha256">65279d4fc5c5b6c9ad8c2b2f35257176720a8cb9dcd360b98f5fe7defca39d84</open-checksum>
+ <location href="repodata/5dfb619f487431ed8697b8351dfc08b8bd1d523a17ea44ce2a19a0a308c04c16-primary.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>3175</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">ae880ec5a096a7e64884ea29c570629f60571171dce67d9255aa914d8e392312</checksum>
+ <open-checksum type="sha256">a66dba7bc865fadc3478db1699616e8fcbe7206a89274fee771861d1ab23bacc</open-checksum>
+ <location href="repodata/ae880ec5a096a7e64884ea29c570629f60571171dce67d9255aa914d8e392312-filelists.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>1170</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">096ae18f96184669091bda3099fad01c34f6979ef0cf845e4d16a2957c866d61</checksum>
+ <open-checksum type="sha256">08c2da0d5990cf0a0851e5a609d722125e6254a15fdd2c6aeec7591ed57af5c9</open-checksum>
+ <location href="repodata/096ae18f96184669091bda3099fad01c34f6979ef0cf845e4d16a2957c866d61-other.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>1149</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+</repomd>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467023</revision>
+ <data type="primary">
+ <checksum type="sha256">935f9df4746c1674c5a07cd2790f4d1ec31a54da08868586cba1fb1c1c428d52</checksum>
+ <open-checksum type="sha256">10081cc658bcfa3df559fc19be3dbdbb943f09d9c8b63f19f524f54b2b8cd7e7</open-checksum>
+ <location href="repodata/935f9df4746c1674c5a07cd2790f4d1ec31a54da08868586cba1fb1c1c428d52-primary.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>1322</size>
+ <open-size>9147</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">e8f85878c5901a3c02e5373fcefb041a80dc8cca78e684592666781729452eb1</checksum>
+ <open-checksum type="sha256">17a856ae9f9704f2391e502a4d57fcc480ff13cf2afe7a6b37c92a91b6ef26aa</open-checksum>
+ <location href="repodata/e8f85878c5901a3c02e5373fcefb041a80dc8cca78e684592666781729452eb1-filelists.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>598</size>
+ <open-size>1533</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">5cc44c658d10d38fadf6bf8ad71668865adefab762fd216430e64331a55dafdf</checksum>
+ <open-checksum type="sha256">7a54cd2ed40eabdb5b16c3e688f810c626333a080f3cb9c85055b050695dbb06</open-checksum>
+ <location href="repodata/5cc44c658d10d38fadf6bf8ad71668865adefab762fd216430e64331a55dafdf-other.xml.gz"/>
+ <timestamp>1528467024</timestamp>
+ <size>598</size>
+ <open-size>1529</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">acde40c6b5b640abc461dfa52da1573940d8b309b1d9096a8f822fa71054a57f</checksum>
+ <open-checksum type="sha256">173952ef2745fba25e88e605d908e2f73d78362c097a4929da0f6082aa093044</open-checksum>
+ <location href="repodata/acde40c6b5b640abc461dfa52da1573940d8b309b1d9096a8f822fa71054a57f-primary.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>3161</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">76ca04b0198da7724c75b7360912e9dcddf68499a4c183a487cdc25a336fec6e</checksum>
+ <open-checksum type="sha256">fa0ee375be1dc2281aa4fa2209115d219af821beef09b2ac66c6c0ef61020dfe</open-checksum>
+ <location href="repodata/76ca04b0198da7724c75b7360912e9dcddf68499a4c183a487cdc25a336fec6e-filelists.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>1156</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">01a1ea0f98f45165e5469df1d5d70d32fe2d2264943cafb6b24e78041ba5c9db</checksum>
+ <open-checksum type="sha256">cd9edb5549e264d16b24c84076478651c8b146a9128414b344d9fba41832c0e3</open-checksum>
+ <location href="repodata/01a1ea0f98f45165e5469df1d5d70d32fe2d2264943cafb6b24e78041ba5c9db-other.sqlite.bz2"/>
+ <timestamp>1528467024</timestamp>
+ <size>1156</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+</repomd>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467023</revision>
+ <data type="primary">
+ <checksum type="sha256">76753a7f9105e5ed8337991367a498ba6843ebe3f0778b9708aab2c4188f87d2</checksum>
+ <open-checksum type="sha256">722c2ef52c5a3b34a7c688d557c61e685525279b32702ce37e779834c1064deb</open-checksum>
+ <location href="repodata/76753a7f9105e5ed8337991367a498ba6843ebe3f0778b9708aab2c4188f87d2-primary.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>1322</size>
+ <open-size>9155</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">1b8d7f694316cdbec76d6c73bc57fb21e2fc3c61cc1e9fa141ed8b5597c43064</checksum>
+ <open-checksum type="sha256">76f894e8e29350610479b16b7755aecbe680dc865b93ea35b746a6d78d7e6b27</open-checksum>
+ <location href="repodata/1b8d7f694316cdbec76d6c73bc57fb21e2fc3c61cc1e9fa141ed8b5597c43064-filelists.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>596</size>
+ <open-size>1541</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">02551ec5b2a6acabac4e4361ec903c7802992c7dfa4eb9f7bc0ab57a929d6bd4</checksum>
+ <open-checksum type="sha256">914ba76d58ddd99ce1caa75b3cd650be727f0484ccfcd5aa020028e12aff0e60</open-checksum>
+ <location href="repodata/02551ec5b2a6acabac4e4361ec903c7802992c7dfa4eb9f7bc0ab57a929d6bd4-other.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>594</size>
+ <open-size>1537</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">6babe0569d363520bb15614564ebe1f650a7e6a9954d4495aa95ab6a095d0407</checksum>
+ <open-checksum type="sha256">cd23129b3ada6f5036dfa2e319d41405d2281bb4e69756e0ba1c99048f983161</open-checksum>
+ <location href="repodata/6babe0569d363520bb15614564ebe1f650a7e6a9954d4495aa95ab6a095d0407-primary.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>3179</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">41385c9995c56b5c0b3bb1fbc467a7574a4fe135c87141b332931c66ad8a2b5a</checksum>
+ <open-checksum type="sha256">703dde684d97a69fcae5fb79870bcbe41e37e8459332e2b774c7a68aae571e38</open-checksum>
+ <location href="repodata/41385c9995c56b5c0b3bb1fbc467a7574a4fe135c87141b332931c66ad8a2b5a-filelists.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>1166</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">93ee02e99edca2f3d0bf9181e3db2a63373114e8b947ef62608fb04a4a1bc735</checksum>
+ <open-checksum type="sha256">3924f3f553fcc0581f3507d9a5d4fdd2577597ae9de2a53c486203710a7744fb</open-checksum>
+ <location href="repodata/93ee02e99edca2f3d0bf9181e3db2a63373114e8b947ef62608fb04a4a1bc735-other.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>1165</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.i686
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.i686
+ - filesystem-0:3.2-40.i686
+ - glibc-0:2.25-4.i686
+ - glibc-common-0:2.25-4.i686
+ - glibc-debuginfo-common-0:2.25-4.i686
+ - kernel-0:4.11.0-1.i686
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.i686
+ - systemd-0:233-3.i686
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467012</revision>
+ <data type="primary">
+ <checksum type="sha256">5da22eedca922651c9d71f60ddec76008be605232430ebf7eac1c98d73e5a191</checksum>
+ <open-checksum type="sha256">dff0a1495dcc6d894f97993565498fb1b9394845abe7e0968da4a3f5e0747b00</open-checksum>
+ <location href="repodata/5da22eedca922651c9d71f60ddec76008be605232430ebf7eac1c98d73e5a191-primary.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>1765</size>
+ <open-size>12751</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">0bd99465a38e120f2473242cad12bfb3b772b24b8ecae39bffbd9cdef9d11f71</checksum>
+ <open-checksum type="sha256">e85b8b186a6f4e98038d5109ee4c2210ebc2eeb6f23fe9afa20123c6b1225212</open-checksum>
+ <location href="repodata/0bd99465a38e120f2473242cad12bfb3b772b24b8ecae39bffbd9cdef9d11f71-filelists.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>847</size>
+ <open-size>2176</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">9b9b45a44325ff1cbfa5021c8cfadad7638397c07c2cba4ec4862e9a20fff668</checksum>
+ <open-checksum type="sha256">2256cfa4c8168d952c66d9ab0a95c80f9cbb924b4d74f94ce4483dd335053843</open-checksum>
+ <location href="repodata/9b9b45a44325ff1cbfa5021c8cfadad7638397c07c2cba4ec4862e9a20fff668-other.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>813</size>
+ <open-size>2125</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">b5cc02335c9184dbec171c140cfb01e027d48f5d4ee3ddc022768f10eadadd8f</checksum>
+ <open-checksum type="sha256">3affad63b91694acd34cd29564745d5dbf33b83baa892654b37741c84843b32b</open-checksum>
+ <location href="repodata/b5cc02335c9184dbec171c140cfb01e027d48f5d4ee3ddc022768f10eadadd8f-primary.sqlite.bz2"/>
+ <timestamp>1528467013</timestamp>
+ <size>3841</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">c159da6b52949d6b9e2fc9c17e1ca904974b97e36b5c3626b557d503e3004834</checksum>
+ <open-checksum type="sha256">b00c92f610914b41c96087d71d80096ef54316ac92f4a41988ba75877150760e</open-checksum>
+ <location href="repodata/c159da6b52949d6b9e2fc9c17e1ca904974b97e36b5c3626b557d503e3004834-filelists.sqlite.bz2"/>
+ <timestamp>1528467013</timestamp>
+ <size>1445</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">f4da985cff145ce4ec4b63175cfd593b99ce4fe51c886367189f2acdbb8b2b2e</checksum>
+ <open-checksum type="sha256">c7f1d45254bbf2d3489abbc180206c4d261a30d6b59baa601ec801e7d97fff6a</open-checksum>
+ <location href="repodata/f4da985cff145ce4ec4b63175cfd593b99ce4fe51c886367189f2acdbb8b2b2e-other.sqlite.bz2"/>
+ <timestamp>1528467013</timestamp>
+ <size>1381</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">290e9c7ad54ffb0267d799c6d5e5f6f0adaeaffdd79f9a3a87a2deb6e676cea7</checksum>
+ <open-checksum type="sha256">f09441f1d27ae1d443c10b5b6e40eaecf09a1323ae1d027053821707bd1a5f31</open-checksum>
+ <location href="repodata/290e9c7ad54ffb0267d799c6d5e5f6f0adaeaffdd79f9a3a87a2deb6e676cea7-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>358</size>
+ <open-size>784</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.s390x
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.s390x
+ - filesystem-0:3.2-40.s390x
+ - glibc-0:2.25-4.s390x
+ - glibc-common-0:2.25-4.s390x
+ - glibc-debuginfo-common-0:2.25-4.s390x
+ - kernel-0:4.11.0-1.s390x
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.s390x
+ - systemd-0:233-3.s390x
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467013</revision>
+ <data type="primary">
+ <checksum type="sha256">f71040c22559fe0075676b32208bf5fb30288a851ed06f00aef5fb87486297f3</checksum>
+ <open-checksum type="sha256">c81b7d86bd497badea956da854cedfffef424165c31a3a686569ca4e014b833e</open-checksum>
+ <location href="repodata/f71040c22559fe0075676b32208bf5fb30288a851ed06f00aef5fb87486297f3-primary.xml.gz"/>
+ <timestamp>1528467014</timestamp>
+ <size>1778</size>
+ <open-size>12799</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">2af29a3797759547f96d5da9aa7a81b2b49e50878f9c7209737b48084ed141b5</checksum>
+ <open-checksum type="sha256">a39e0ea579555b1e0a39fb3651da453c5e355a2a510a32f410c5a0eadc7aed1f</open-checksum>
+ <location href="repodata/2af29a3797759547f96d5da9aa7a81b2b49e50878f9c7209737b48084ed141b5-filelists.xml.gz"/>
+ <timestamp>1528467014</timestamp>
+ <size>849</size>
+ <open-size>2187</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">4b15355abdab48ad730e33090f1efbec3999353e01039a8cbee28150c761caac</checksum>
+ <open-checksum type="sha256">6b54a04791df0bbaa7cac17be56abbe020001ecb23a4de4d8bf2d47540bcd6b1</open-checksum>
+ <location href="repodata/4b15355abdab48ad730e33090f1efbec3999353e01039a8cbee28150c761caac-other.xml.gz"/>
+ <timestamp>1528467014</timestamp>
+ <size>811</size>
+ <open-size>2134</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">e8bcdb6cea307ff90c3a62290701a75eb41515770e01384a00b2c260bea30bda</checksum>
+ <open-checksum type="sha256">fad26bf2d0ec29500d442df1d3c8962b5b109193458c45b75bab96abe872e3ef</open-checksum>
+ <location href="repodata/e8bcdb6cea307ff90c3a62290701a75eb41515770e01384a00b2c260bea30bda-primary.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>3848</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">eecb72efa7593c66ba79a31710f7557060ddd2349fb354ee072e5e9915a2fef0</checksum>
+ <open-checksum type="sha256">90e6509df19deb43579ae7789cd86147d93af5ff8e1c6fb6f00f1d21e1e3fca8</open-checksum>
+ <location href="repodata/eecb72efa7593c66ba79a31710f7557060ddd2349fb354ee072e5e9915a2fef0-filelists.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>1452</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">9af251c9d796b28d8045301069ef24001d66119fb81bdb7a9cb2ad8308f34911</checksum>
+ <open-checksum type="sha256">317bab92b97f0e62cbe615606b6c56835eacb8c6eecb0f69d82d389b5b154ae6</open-checksum>
+ <location href="repodata/9af251c9d796b28d8045301069ef24001d66119fb81bdb7a9cb2ad8308f34911-other.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>1386</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">c8ab38018567345263fe704c401524d1fe9545b6471692b28e9524c0a23cd80b</checksum>
+ <open-checksum type="sha256">ff7aa499590467728d58a132dcd743f3af4984ac4ff4354e5c37f43fc980c8d6</open-checksum>
+ <location href="repodata/c8ab38018567345263fe704c401524d1fe9545b6471692b28e9524c0a23cd80b-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>358</size>
+ <open-size>794</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - basesystem-0:11-3.src
+ - bash-0:4.4.12-2.src
+ - bash-doc-0:4.4.12-2.noarch
+ - filesystem-0:3.2-40.src
+ - glibc-0:2.25-4.src
+ - kernel-0:4.11.0-1.src
+ - kernel-doc-0:4.11.0-1.noarch
+ - systemd-0:233-3.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.x86_64
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25-4.x86_64
+ - filesystem-0:3.2-40.x86_64
+ - glibc-0:2.25-4.x86_64
+ - glibc-common-0:2.25-4.x86_64
+ - glibc-debuginfo-common-0:2.25-4.x86_64
+ - kernel-0:4.11.0-1.x86_64
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.x86_64
+ - systemd-0:233-3.x86_64
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467012</revision>
+ <data type="primary">
+ <checksum type="sha256">5fb61d376156ab4ce31330757f19e57378cc885597413ad787f5277fbf7280b1</checksum>
+ <open-checksum type="sha256">49dc09dc12c349322ccf2ede7f6edeaa4ae18ff78fa152579ccf03ce44651477</open-checksum>
+ <location href="repodata/5fb61d376156ab4ce31330757f19e57378cc885597413ad787f5277fbf7280b1-primary.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>1780</size>
+ <open-size>12808</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">29ab3a3a200636de5a429bcf221ef71c0b522b150dbb9a2a9ae52de381880f0d</checksum>
+ <open-checksum type="sha256">1f68ba6e79ad73a91d80eb311744271ed5f0c3ff914824c41f15cd6a89b25f32</open-checksum>
+ <location href="repodata/29ab3a3a200636de5a429bcf221ef71c0b522b150dbb9a2a9ae52de381880f0d-filelists.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>849</size>
+ <open-size>2196</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">6fd2b7ce8c8d049bae4d7e0b398148d71c01fd28ac0d2524e609aadb5dab3052</checksum>
+ <open-checksum type="sha256">37a1e3d548054f4b967621e45eeca250d9e7986f8db7d81e33bf2d0bf2fa9bdd</open-checksum>
+ <location href="repodata/6fd2b7ce8c8d049bae4d7e0b398148d71c01fd28ac0d2524e609aadb5dab3052-other.xml.gz"/>
+ <timestamp>1528467013</timestamp>
+ <size>812</size>
+ <open-size>2143</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">bea9d5e3288aaf0115434606cef08896fc0384149bf873547ef10cd27ba815e6</checksum>
+ <open-checksum type="sha256">34a23bac873440ca65029db2de7ec25c7daca5165ccf3ac3df9f81cae2080e77</open-checksum>
+ <location href="repodata/bea9d5e3288aaf0115434606cef08896fc0384149bf873547ef10cd27ba815e6-primary.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>3833</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">d7307716cc7ee39258a94c534a7a5c6bcd442d2cb0a0cdc1c234877691e148c8</checksum>
+ <open-checksum type="sha256">121db48a9e8f1a536a913e9c37e9297bcde573942bf42845d1ce214d0e471247</open-checksum>
+ <location href="repodata/d7307716cc7ee39258a94c534a7a5c6bcd442d2cb0a0cdc1c234877691e148c8-filelists.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>1493</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">e7a8e17dd64ba565a84139cf92a9a543a8a17bddc0e6332fbcd1bfe20a77d7d2</checksum>
+ <open-checksum type="sha256">0fa854a5507c0a6f8157260c3f461472f50f6955e0dfa5c0b1c45dcbe7e9b7af</open-checksum>
+ <location href="repodata/e7a8e17dd64ba565a84139cf92a9a543a8a17bddc0e6332fbcd1bfe20a77d7d2-other.sqlite.bz2"/>
+ <timestamp>1528467014</timestamp>
+ <size>1389</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">2701513854bc03cd5f978041407e1c25a780abf79e62f1d2304abd49fb030bfe</checksum>
+ <open-checksum type="sha256">d00e3c478a678b7de02f7779805cab8ad830237ed04911fec3e258affc67529a</open-checksum>
+ <location href="repodata/2701513854bc03cd5f978041407e1c25a780abf79e62f1d2304abd49fb030bfe-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>361</size>
+ <open-size>804</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.i686
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.i686
+ - filesystem-0:3.2-40.i686
+ - glibc-0:2.25.90-2.i686
+ - glibc-common-0:2.25.90-2.i686
+ - glibc-debuginfo-common-0:2.25.90-2.i686
+ - kernel-0:4.11.0-1.i686
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.i686
+ - systemd-0:233-3.i686
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467014</revision>
+ <data type="primary">
+ <checksum type="sha256">2c646459aed861bcfedd9538ad43c4e06cecc0d8bf50ff88a42ce92c093c3cf1</checksum>
+ <open-checksum type="sha256">217e2144e6efd58cfa4b64ce97f56ac3a5549cf32029ea164e60153628bab822</open-checksum>
+ <location href="repodata/2c646459aed861bcfedd9538ad43c4e06cecc0d8bf50ff88a42ce92c093c3cf1-primary.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>1762</size>
+ <open-size>12814</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">ed6d0a90af4f1a1d7577763077717f4e8c9e9118b7e815824c488825d3f40541</checksum>
+ <open-checksum type="sha256">f718d66710c00cb7770b65c80e82fde0e90daf94770d368e31e96df3c0ca3de5</open-checksum>
+ <location href="repodata/ed6d0a90af4f1a1d7577763077717f4e8c9e9118b7e815824c488825d3f40541-filelists.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>847</size>
+ <open-size>2188</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">f0cc45d85b3e8db94359796062b716f2ee68f23e1ce6b05e229faa7f0b653878</checksum>
+ <open-checksum type="sha256">977855eb21ed15fb3e39719e4e3eb31a43f2d17a1a373a925af46d0e045fadd5</open-checksum>
+ <location href="repodata/f0cc45d85b3e8db94359796062b716f2ee68f23e1ce6b05e229faa7f0b653878-other.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>809</size>
+ <open-size>2137</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">b85a173d4d57c2d4b09e252de36f24f38cf0f5b6194a12b7d95aacf312f21004</checksum>
+ <open-checksum type="sha256">52cec508d560bfeb5dce35350a019b683e7fde0104225e8cb5b2863032895b74</open-checksum>
+ <location href="repodata/b85a173d4d57c2d4b09e252de36f24f38cf0f5b6194a12b7d95aacf312f21004-primary.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>3837</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">e3d0d959c1b041e215dbf37172d389b10035b02ed0312569842e9fdbd117b812</checksum>
+ <open-checksum type="sha256">e8813fec7df0c4839f03fd130eabaac9b6101595ffe4aedbfa36a871d56a891a</open-checksum>
+ <location href="repodata/e3d0d959c1b041e215dbf37172d389b10035b02ed0312569842e9fdbd117b812-filelists.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>1500</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">a8239c88869b30de18e2241890cd3543e1525e41991c99068022a4117505bcf5</checksum>
+ <open-checksum type="sha256">ffc33df8d985115c8978f059b84ce3c2ea97fe43ef7dcf4164698a512a82cfb7</open-checksum>
+ <location href="repodata/a8239c88869b30de18e2241890cd3543e1525e41991c99068022a4117505bcf5-other.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>1411</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">3f5fbc10b586ac5d557e8e423c07b323c6ccdfc065fa5a38942ffddc56c6dec5</checksum>
+ <open-checksum type="sha256">786f8f3d0989d99f79225b12c183c63a133206e303961ec96107e80b1f2e6072</open-checksum>
+ <location href="repodata/3f5fbc10b586ac5d557e8e423c07b323c6ccdfc065fa5a38942ffddc56c6dec5-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>358</size>
+ <open-size>796</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.s390x
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.s390x
+ - filesystem-0:3.2-40.s390x
+ - glibc-0:2.25.90-2.s390x
+ - glibc-common-0:2.25.90-2.s390x
+ - glibc-debuginfo-common-0:2.25.90-2.s390x
+ - kernel-0:4.11.0-1.s390x
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.s390x
+ - systemd-0:233-3.s390x
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467015</revision>
+ <data type="primary">
+ <checksum type="sha256">4b07987399cff660d9e144d0a44c6ceba3c10642d0b82523d3131f9895d89780</checksum>
+ <open-checksum type="sha256">2d84b127e6a1dd7b8ddfe7ca5084a044922f6b74adb1d2d80d981d2b30334035</open-checksum>
+ <location href="repodata/4b07987399cff660d9e144d0a44c6ceba3c10642d0b82523d3131f9895d89780-primary.xml.gz"/>
+ <timestamp>1528467016</timestamp>
+ <size>1779</size>
+ <open-size>12862</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">6922ea6fc78050b5726b7efcc48448535a6bb9461bb5cd8ecec954a65ea57305</checksum>
+ <open-checksum type="sha256">018ca4bed8ed74f7c0d27526871d53384e1fae8b8ea3b8b7360f561e6b86ff58</open-checksum>
+ <location href="repodata/6922ea6fc78050b5726b7efcc48448535a6bb9461bb5cd8ecec954a65ea57305-filelists.xml.gz"/>
+ <timestamp>1528467016</timestamp>
+ <size>850</size>
+ <open-size>2199</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">10a489e767aefa063ebc4a8e6650a635a7534a5579690e831c71988a2a801eae</checksum>
+ <open-checksum type="sha256">0694c5b19c45741c1c8c5da0ab22eb38bd483960872a329c2334f6bf9c1ffde7</open-checksum>
+ <location href="repodata/10a489e767aefa063ebc4a8e6650a635a7534a5579690e831c71988a2a801eae-other.xml.gz"/>
+ <timestamp>1528467016</timestamp>
+ <size>812</size>
+ <open-size>2146</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">11161c3a866a02ec7a6f84ad1a6111348abdb6e89634f3e07ed1cce2750065cf</checksum>
+ <open-checksum type="sha256">031e0b7fa02ec15f6c25635fc77763de66059833c78c0ab14f3f024203d2e7c2</open-checksum>
+ <location href="repodata/11161c3a866a02ec7a6f84ad1a6111348abdb6e89634f3e07ed1cce2750065cf-primary.sqlite.bz2"/>
+ <timestamp>1528467016</timestamp>
+ <size>3825</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">cae4b2e914c0341bf033c733555e06b64329baa1024dab16b2c4f5951f05334a</checksum>
+ <open-checksum type="sha256">4190675d8911642949411d31e535e22e9f4422140a9a89df033fd7fe0d923462</open-checksum>
+ <location href="repodata/cae4b2e914c0341bf033c733555e06b64329baa1024dab16b2c4f5951f05334a-filelists.sqlite.bz2"/>
+ <timestamp>1528467016</timestamp>
+ <size>1485</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">3b9a21f2174811d9077ee95afd017d6cd1cd6f5a38cf91f1c9baa91799bae176</checksum>
+ <open-checksum type="sha256">813c982ddd4f381799942b2dc79bc10767dd0a777914729b07f75e6b8b47be5c</open-checksum>
+ <location href="repodata/3b9a21f2174811d9077ee95afd017d6cd1cd6f5a38cf91f1c9baa91799bae176-other.sqlite.bz2"/>
+ <timestamp>1528467016</timestamp>
+ <size>1407</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">e015590a3ac04f560d4ed2b5e616b9c5484554a3d9f6664184e375e760774b52</checksum>
+ <open-checksum type="sha256">1ba12091166b231c7871cc1b89a94ebca53ebac3b54424eca98e78d88415aaf9</open-checksum>
+ <location href="repodata/e015590a3ac04f560d4ed2b5e616b9c5484554a3d9f6664184e375e760774b52-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>359</size>
+ <open-size>806</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - basesystem-0:11-3.src
+ - bash-0:4.4.12-2.src
+ - bash-doc-0:4.4.12-2.noarch
+ - filesystem-0:3.2-40.src
+ - glibc-0:2.25.90-2.src
+ - kernel-0:4.11.0-1.src
+ - kernel-doc-0:4.11.0-1.noarch
+ - systemd-0:233-3.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: f26
+ version: 2
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:11-3.noarch
+ - bash-0:4.4.12-2.x86_64
+ - bash-doc-0:4.4.12-2.noarch
+ - dummy-nscd-0:2.25.90-2.x86_64
+ - filesystem-0:3.2-40.x86_64
+ - glibc-0:2.25.90-2.x86_64
+ - glibc-common-0:2.25.90-2.x86_64
+ - glibc-debuginfo-common-0:2.25.90-2.x86_64
+ - kernel-0:4.11.0-1.x86_64
+ - kernel-doc-0:4.11.0-1.noarch
+ - kernel-headers-0:4.11.0-1.x86_64
+ - systemd-0:233-3.x86_64
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467014</revision>
+ <data type="primary">
+ <checksum type="sha256">b947070a1412451590f1d2422af262833163e19cc49428568e242c7dcfb10d89</checksum>
+ <open-checksum type="sha256">44b829432791921332c30bda967174563a0e259f3261323a25de3eb413f1ea2f</open-checksum>
+ <location href="repodata/b947070a1412451590f1d2422af262833163e19cc49428568e242c7dcfb10d89-primary.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>1781</size>
+ <open-size>12871</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">41398af18302111ad8d542b137ce234556c6693fbb66ea01084d9224a2399c87</checksum>
+ <open-checksum type="sha256">c8baf2bd64b2ed91a30e0c93a03ab4df29975b70339e4a0a8f835eb1ed7e9818</open-checksum>
+ <location href="repodata/41398af18302111ad8d542b137ce234556c6693fbb66ea01084d9224a2399c87-filelists.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>851</size>
+ <open-size>2208</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">b64e102539e600b45cbed904bd8e07d3fa9580dbcf0ddf73d02af5a82ecc72fa</checksum>
+ <open-checksum type="sha256">2ea6e7e5da9f6a91ca8d2384d0c6658bab09c0ede96f2c94fca466695132b7a9</open-checksum>
+ <location href="repodata/b64e102539e600b45cbed904bd8e07d3fa9580dbcf0ddf73d02af5a82ecc72fa-other.xml.gz"/>
+ <timestamp>1528467015</timestamp>
+ <size>812</size>
+ <open-size>2155</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">3ca1bd0336c7e5a6d2453284ff02b02404ebfb4472dd1b0d2663ee9c09276607</checksum>
+ <open-checksum type="sha256">923cddddf01a5f32421890f9ede5f3f5d70349391f03e9417aa2c0fb8d5ea2b6</open-checksum>
+ <location href="repodata/3ca1bd0336c7e5a6d2453284ff02b02404ebfb4472dd1b0d2663ee9c09276607-primary.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>3854</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">25ea3a56d1c431e747089ec10810e2369347aa8a0d0bc49e8ab06a9bc22d38bd</checksum>
+ <open-checksum type="sha256">741ba0383e334931449154190e13d5a89fc825b6f65de7edf716cb6bccd4ec4f</open-checksum>
+ <location href="repodata/25ea3a56d1c431e747089ec10810e2369347aa8a0d0bc49e8ab06a9bc22d38bd-filelists.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>1483</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">65f0a3c92f1d21b30328e65acf3472ba62df03621302eecd36509c9fb4e9c83b</checksum>
+ <open-checksum type="sha256">b5559f4dab0c11cac91783b1f8e91601ff732eb6fa02b6d508cdb779399ec229</open-checksum>
+ <location href="repodata/65f0a3c92f1d21b30328e65acf3472ba62df03621302eecd36509c9fb4e9c83b-other.sqlite.bz2"/>
+ <timestamp>1528467015</timestamp>
+ <size>1415</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">02ec627b4e841a824c34f245d977a9d7e69fd696760afbf3a6eed84157f2bf0e</checksum>
+ <open-checksum type="sha256">c2d04e54139f20390789e2fddfd85ed68a2b5a08aff02affdf0edf15829228a8</open-checksum>
+ <location href="repodata/02ec627b4e841a824c34f245d977a9d7e69fd696760afbf3a6eed84157f2bf0e-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>362</size>
+ <open-size>816</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.i686
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.i686
+ - filesystem-0:3.2-21.i686
+ - glibc-0:2.17-157.i686
+ - glibc-common-0:2.17-157.i686
+ - glibc-debuginfo-common-0:2.17-157.i686
+ - kernel-0:3.10.0-514.i686
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.i686
+ - systemd-0:219-30.i686
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467016</revision>
+ <data type="primary">
+ <checksum type="sha256">eb51feee7374573f8f0bd141ce87f12be7542a8385ea499eb888be375aaadf98</checksum>
+ <open-checksum type="sha256">62218a340e6c233d1652d790a69434510d320f3c4f7de5562e7478abdfb8b062</open-checksum>
+ <location href="repodata/eb51feee7374573f8f0bd141ce87f12be7542a8385ea499eb888be375aaadf98-primary.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>1754</size>
+ <open-size>12843</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">c5a73eed1091cadc2d6a11497a0c83fdd9750d652c019b86955a38b0451ef21b</checksum>
+ <open-checksum type="sha256">cf63aa70cc7b7052a823f3664d8672ffefbcc48db0517032625015be22ab28b5</open-checksum>
+ <location href="repodata/c5a73eed1091cadc2d6a11497a0c83fdd9750d652c019b86955a38b0451ef21b-filelists.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>848</size>
+ <open-size>2195</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">f0f5c32d3dfe340a88be037ef1cc3f270ab8e967ba848d17117d7ee2dca7fb32</checksum>
+ <open-checksum type="sha256">3de9b5339548daffe78ab6990669d56a1e016ade04b00d184d273d5599924d41</open-checksum>
+ <location href="repodata/f0f5c32d3dfe340a88be037ef1cc3f270ab8e967ba848d17117d7ee2dca7fb32-other.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>810</size>
+ <open-size>2144</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">81a44a582fc126bb7ce5785ea41c028a458e2f1cfcdb9176981f3e8504da81cc</checksum>
+ <open-checksum type="sha256">27029930f91be35b270ca600acfb71d1bf45e24846c0970e1ee7897146ead1a1</open-checksum>
+ <location href="repodata/81a44a582fc126bb7ce5785ea41c028a458e2f1cfcdb9176981f3e8504da81cc-primary.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>3841</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">9db4910badc4de5bbfd4a1aefd85d164d5580fa1093c1cfeee9991485dac25a0</checksum>
+ <open-checksum type="sha256">9586eaae11a5c6189e37ce70954023c50b3018e2275ebe7476fbc4b54362cb8b</open-checksum>
+ <location href="repodata/9db4910badc4de5bbfd4a1aefd85d164d5580fa1093c1cfeee9991485dac25a0-filelists.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>1488</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">a3628a8e0fa6cf952021c2aab864aff84c8e3456f392ff52b37be7cda7c9efb5</checksum>
+ <open-checksum type="sha256">c8d52b8ddd29400b75ce51b1db92088a360bd5fc05da194219c104a02433a6ed</open-checksum>
+ <location href="repodata/a3628a8e0fa6cf952021c2aab864aff84c8e3456f392ff52b37be7cda7c9efb5-other.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>1409</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">3a212be1927ef000edb547d1be028f0fa12f44cab57feeb4c3e40602c13cd07c</checksum>
+ <open-checksum type="sha256">6a53071b6d9fdfe5e6484fe91eb385ca57262dc98d166d5d599764f7662fbc75</open-checksum>
+ <location href="repodata/3a212be1927ef000edb547d1be028f0fa12f44cab57feeb4c3e40602c13cd07c-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>363</size>
+ <open-size>806</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.s390x
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.s390x
+ - filesystem-0:3.2-21.s390x
+ - glibc-0:2.17-157.s390x
+ - glibc-common-0:2.17-157.s390x
+ - glibc-debuginfo-common-0:2.17-157.s390x
+ - kernel-0:3.10.0-514.s390x
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.s390x
+ - systemd-0:219-30.s390x
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467017</revision>
+ <data type="primary">
+ <checksum type="sha256">8a03380707a74f5335d064b6902086bd06d4c57b3196f314bca3ca386df3618f</checksum>
+ <open-checksum type="sha256">af5a6acd4637a9c083f4afcf1d195dfa5324080b097e0c635fc401c947e55f76</open-checksum>
+ <location href="repodata/8a03380707a74f5335d064b6902086bd06d4c57b3196f314bca3ca386df3618f-primary.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>1774</size>
+ <open-size>12891</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">84c169e08837b770e5fa68e856ca0b579357feeb477d1ddc1006cf2aa8ab1326</checksum>
+ <open-checksum type="sha256">47ad251854c7c2a03eef08cc897568437d41c1b6ba2f90a897acbd828bd6537f</open-checksum>
+ <location href="repodata/84c169e08837b770e5fa68e856ca0b579357feeb477d1ddc1006cf2aa8ab1326-filelists.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>846</size>
+ <open-size>2206</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">50251017cd9f26335d97e8bb833645a929d2dc8d3beadf4cd90458dedf515180</checksum>
+ <open-checksum type="sha256">2b1359435e91554011b61f5bc10a3b6a56e188bda0b93e4071fa62d5178e382b</open-checksum>
+ <location href="repodata/50251017cd9f26335d97e8bb833645a929d2dc8d3beadf4cd90458dedf515180-other.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>808</size>
+ <open-size>2153</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">152d04693f3af3745e4c6ad6c97016d2fbd53b37ce15ed05bc43f4af9c82ffc1</checksum>
+ <open-checksum type="sha256">9d8be3fc9b0a7546170c804f04be64592d0b7a9dcae1bd34d0c720623a2da8a6</open-checksum>
+ <location href="repodata/152d04693f3af3745e4c6ad6c97016d2fbd53b37ce15ed05bc43f4af9c82ffc1-primary.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>3879</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">785b60c3c4654685256fd185979a315c90cfdda605b7481dedb611bc31f3410b</checksum>
+ <open-checksum type="sha256">d557a01e69c1d6ba24e124ce2cbe977389c87ca252c087aaf63cbeaad7206387</open-checksum>
+ <location href="repodata/785b60c3c4654685256fd185979a315c90cfdda605b7481dedb611bc31f3410b-filelists.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>1480</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">367ab55c377a9215a6d0226a11eda1f5448982bdab7065f4824a7f979595c7ae</checksum>
+ <open-checksum type="sha256">b8c1cc11132ec20adfdc7eecb8cb86333d285f456e5b5a228fa1e1b8f9ff55f2</open-checksum>
+ <location href="repodata/367ab55c377a9215a6d0226a11eda1f5448982bdab7065f4824a7f979595c7ae-other.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>1393</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">49330a2d118f8e9e3b650f25ebaad6f5f6442d309a8d4e370d6738d4b9fa0432</checksum>
+ <open-checksum type="sha256">eef52b2fef393b48db372450027e703b5c9c6ef2bf7f1b426be30f550c04c6e7</open-checksum>
+ <location href="repodata/49330a2d118f8e9e3b650f25ebaad6f5f6442d309a8d4e370d6738d4b9fa0432-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>364</size>
+ <open-size>816</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - basesystem-0:10.0-7.src
+ - bash-0:4.2.46-21.src
+ - bash-doc-0:4.2.46-21.noarch
+ - filesystem-0:3.2-21.src
+ - glibc-0:2.17-157.src
+ - kernel-0:3.10.0-514.src
+ - kernel-doc-0:3.10.0-514.noarch
+ - systemd-0:219-30.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: base-runtime
+ stream: rhel73
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ profiles:
+ default:
+ rpms:
+ - bash
+ - glibc
+ - kernel
+ - systemd
+ minimal:
+ rpms:
+ - glibc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - basesystem-0:10.0-7.noarch
+ - bash-0:4.2.46-21.x86_64
+ - bash-doc-0:4.2.46-21.noarch
+ - dummy-nscd-0:2.17-157.x86_64
+ - filesystem-0:3.2-21.x86_64
+ - glibc-0:2.17-157.x86_64
+ - glibc-common-0:2.17-157.x86_64
+ - glibc-debuginfo-common-0:2.17-157.x86_64
+ - kernel-0:3.10.0-514.x86_64
+ - kernel-doc-0:3.10.0-514.noarch
+ - kernel-headers-0:3.10.0-514.x86_64
+ - systemd-0:219-30.x86_64
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467017</revision>
+ <data type="primary">
+ <checksum type="sha256">fb2a6d2c1b9e1102963a1c85c16ea6dfa255cee6506406ccf34a55237e1514f7</checksum>
+ <open-checksum type="sha256">204e9cecf141bde61b55a92f6ec02ea9af42cccb73a0c18a9ae22b52e221be52</open-checksum>
+ <location href="repodata/fb2a6d2c1b9e1102963a1c85c16ea6dfa255cee6506406ccf34a55237e1514f7-primary.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>1769</size>
+ <open-size>12900</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">ea4391fbe23bc6864552592fdc6b2b3175acf2ba8ea9b2ceea24a5035670d4ed</checksum>
+ <open-checksum type="sha256">2bf554d19dbb6c0ccee66bc9d669ffea6e8ff768fe932ff789edbce190c71ba2</open-checksum>
+ <location href="repodata/ea4391fbe23bc6864552592fdc6b2b3175acf2ba8ea9b2ceea24a5035670d4ed-filelists.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>845</size>
+ <open-size>2215</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">efad95bf718650757aaf128a50541a5986ebbb5a42f2b552381b6e36eb89a941</checksum>
+ <open-checksum type="sha256">5a2f81e441d028dcaf6c5688a37e23d902edbee9533c0228163771a399d34e60</open-checksum>
+ <location href="repodata/efad95bf718650757aaf128a50541a5986ebbb5a42f2b552381b6e36eb89a941-other.xml.gz"/>
+ <timestamp>1528467017</timestamp>
+ <size>804</size>
+ <open-size>2162</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">4a36be3446bb1c0c556bfdaddd174262baffe920ce0e98ebffcd16b932929294</checksum>
+ <open-checksum type="sha256">0dc5f6a1e5b35486b48212aa89c8036039ce2b88ea957bb5287b67218de6af7d</open-checksum>
+ <location href="repodata/4a36be3446bb1c0c556bfdaddd174262baffe920ce0e98ebffcd16b932929294-primary.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>3858</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">0ba33f69df15c52810c926a90d28b44c37da3d56fd772a681f354d517d2b499c</checksum>
+ <open-checksum type="sha256">3ba3f8cb7d353af7f89bfa0ba3190fd784a2720f0cccb0e8663a9c5ef7cf5939</open-checksum>
+ <location href="repodata/0ba33f69df15c52810c926a90d28b44c37da3d56fd772a681f354d517d2b499c-filelists.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>1477</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">9d9fe100426ee8ea2b7c4484bd3567caebab9efd5d8356531bc7f9562860eef3</checksum>
+ <open-checksum type="sha256">b4ef08d420903c32841d4f71950b2740c5b437661f8fd12ef41b6676b7d28f3f</open-checksum>
+ <location href="repodata/9d9fe100426ee8ea2b7c4484bd3567caebab9efd5d8356531bc7f9562860eef3-other.sqlite.bz2"/>
+ <timestamp>1528467017</timestamp>
+ <size>1375</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">b9c794d1e56cb24aa92eefc14899370ac651950f13d38edfc5af0306e5d308cf</checksum>
+ <open-checksum type="sha256">ec51f6e90d8a92eb010e4c5af0059c69c799f65d70d9d0a7d27dbcee98c5581c</open-checksum>
+ <location href="repodata/b9c794d1e56cb24aa92eefc14899370ac651950f13d38edfc5af0306e5d308cf-modules.yaml.gz"/>
+ <timestamp>1531828716</timestamp>
+ <size>368</size>
+ <open-size>826</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.i686
+ - httpd-doc-0:2.2.15-59.i686
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467018</revision>
+ <data type="primary">
+ <checksum type="sha256">406cccd510cff9f9d92a8a493624aea3a0c9a94c6827ccbbe0b69d40f0c8665b</checksum>
+ <open-checksum type="sha256">a49107373c975c0941ab795eadf2142758a23f9ca3512d419bb26c3259712c29</open-checksum>
+ <location href="repodata/406cccd510cff9f9d92a8a493624aea3a0c9a94c6827ccbbe0b69d40f0c8665b-primary.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>709</size>
+ <open-size>2288</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">03fc6ad0f80026d72250a47548078e9612031fc8dfad101b6ca40542ac9e443d</checksum>
+ <open-checksum type="sha256">bba5253e116a5166ffcf8fdfb9db9a7e823237c24cf965e007b83598517aa792</open-checksum>
+ <location href="repodata/03fc6ad0f80026d72250a47548078e9612031fc8dfad101b6ca40542ac9e443d-filelists.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>281</size>
+ <open-size>457</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">32afd669744ee4e82988d9133e1dcf227b8f34b6b0b56520730bbf32ec2bb163</checksum>
+ <open-checksum type="sha256">c253c3599f5586826acbc3845633331571378776d81dea5aa44ba10e0f40b082</open-checksum>
+ <location href="repodata/32afd669744ee4e82988d9133e1dcf227b8f34b6b0b56520730bbf32ec2bb163-other.xml.gz"/>
+ <timestamp>1528467018</timestamp>
+ <size>281</size>
+ <open-size>453</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">349e47ae3b916ffda1663b6cd9b3cb48f071ffcd933d925551ee347d21e803d1</checksum>
+ <open-checksum type="sha256">33726045c4f6874f10e06e8d842687bffd6fa0bf5437e88d21f2f0d1ac3f11e8</open-checksum>
+ <location href="repodata/349e47ae3b916ffda1663b6cd9b3cb48f071ffcd933d925551ee347d21e803d1-primary.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>2009</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">9f95de36bcaf98a0fc3e8483ada52c715916b060820a4309efe3a0687c851c4b</checksum>
+ <open-checksum type="sha256">49aa0f7d81989b644da0b53a39751b1d9f9cd307be4cd620fcb8acbd991146f5</open-checksum>
+ <location href="repodata/9f95de36bcaf98a0fc3e8483ada52c715916b060820a4309efe3a0687c851c4b-filelists.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>761</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">5fc06cb7cfbeac4e777ea42590c892035eb95329ee0b7da2e4ddef3da04ab0e9</checksum>
+ <open-checksum type="sha256">d85f791b834c792464e180769811de4a77ee6fe55583e5a81a96d4ccc05db04c</open-checksum>
+ <location href="repodata/5fc06cb7cfbeac4e777ea42590c892035eb95329ee0b7da2e4ddef3da04ab0e9-other.sqlite.bz2"/>
+ <timestamp>1528467018</timestamp>
+ <size>739</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">2d442fe4da23ac7f985e87b6117e11d32cd66e8d69fc7a7c30b0635e2b1dac4d</checksum>
+ <open-checksum type="sha256">95b76e2d493f3eb70f6b5d23c9a2ba2e20e0db36be2db6145d6e7c99ae3009e7</open-checksum>
+ <location href="repodata/2d442fe4da23ac7f985e87b6117e11d32cd66e8d69fc7a7c30b0635e2b1dac4d-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>266</size>
+ <open-size>465</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.s390x
+ - httpd-doc-0:2.2.15-59.s390x
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467019</revision>
+ <data type="primary">
+ <checksum type="sha256">d01175c963911d4feace8e30a699f870d3d815f48c37230c81dbe6bad595dd06</checksum>
+ <open-checksum type="sha256">fb5426b4b984cfa039a4ec4d47c93a45dd0388e0b9eccc18c95c7ecbbcfd415d</open-checksum>
+ <location href="repodata/d01175c963911d4feace8e30a699f870d3d815f48c37230c81dbe6bad595dd06-primary.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>708</size>
+ <open-size>2294</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">da9f29cfe99a1ed025c73cf82945a685aa3e2164509fe1b7bba24b735469d1f9</checksum>
+ <open-checksum type="sha256">475d46b12de29404dca4ffdf933318d0459dd8018980c7a58c9175455dbeb49c</open-checksum>
+ <location href="repodata/da9f29cfe99a1ed025c73cf82945a685aa3e2164509fe1b7bba24b735469d1f9-filelists.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>282</size>
+ <open-size>459</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">13e3f7c04b46c1682182e4d566add538d1d8ed37e61f7dbdc6e16aeaa4768805</checksum>
+ <open-checksum type="sha256">ab38e84274b93556fd50b76b44853885018eef718bd01f4f80ce104f4cf1c94b</open-checksum>
+ <location href="repodata/13e3f7c04b46c1682182e4d566add538d1d8ed37e61f7dbdc6e16aeaa4768805-other.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>281</size>
+ <open-size>455</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">bc47c370a43f00aed37066c4a4ed16549985892deb8ebbe300e644553fef5658</checksum>
+ <open-checksum type="sha256">7adde6252385429fe5c2e1914d5b03d7de4c6af7442529d3f03dc71cb9aafe91</open-checksum>
+ <location href="repodata/bc47c370a43f00aed37066c4a4ed16549985892deb8ebbe300e644553fef5658-primary.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>2016</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">acee6d3b27377f84fcfccb87b8f457c2def0851908367a5025c5b5e66e6f8a7f</checksum>
+ <open-checksum type="sha256">4bace08963d42824c4cba3b942bc53ac99687a8e1140937f984efb2d2dc6f292</open-checksum>
+ <location href="repodata/acee6d3b27377f84fcfccb87b8f457c2def0851908367a5025c5b5e66e6f8a7f-filelists.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>763</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">e22de26db83948d25ec12d327c1794f8cad18c14f7021e5428306dd4a456f7c4</checksum>
+ <open-checksum type="sha256">fb86dfe21da8f237992cc0352c6a9dd1350558b295fefbcb8a9728a34dcf1ac0</open-checksum>
+ <location href="repodata/e22de26db83948d25ec12d327c1794f8cad18c14f7021e5428306dd4a456f7c4-other.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>732</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">1870278259386f08c27583d2575457f185d065fff15526a93fe30652a747d1a7</checksum>
+ <open-checksum type="sha256">acf732b8ab840c475394aef2e522166a0833b266ebd42c75325dabd1b9fed15a</open-checksum>
+ <location href="repodata/1870278259386f08c27583d2575457f185d065fff15526a93fe30652a747d1a7-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>266</size>
+ <open-size>468</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.2
+ version: 1
+ context: e3b0c442
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: []
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.2.15-59.x86_64
+ - httpd-doc-0:2.2.15-59.x86_64
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467018</revision>
+ <data type="primary">
+ <checksum type="sha256">42dfbd1f0acf7e60911c0cf4b6ad1ead428942ff45ea1cac17ddbc9597560704</checksum>
+ <open-checksum type="sha256">ed7b471dc655638a913c4b98cb4ba0e3fb64a5b9a42b26f1c997eb15e056c6ab</open-checksum>
+ <location href="repodata/42dfbd1f0acf7e60911c0cf4b6ad1ead428942ff45ea1cac17ddbc9597560704-primary.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>710</size>
+ <open-size>2296</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">0634a236b57c9970e8236ecfd2863644b4312e75a68d4f8755308a570658acfc</checksum>
+ <open-checksum type="sha256">d97cbc9ddea65f9864fc70214fb5d3f42f584d66414446315ff64b22276fc98e</open-checksum>
+ <location href="repodata/0634a236b57c9970e8236ecfd2863644b4312e75a68d4f8755308a570658acfc-filelists.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>284</size>
+ <open-size>461</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">1f66590abb9d80a053e36fbbcd54e0c7cf69e2253e285598aa402d742302b3e2</checksum>
+ <open-checksum type="sha256">917c112272bbf8b1618047e4513e189862fb80f501c2f3368942dc3dde1b698a</open-checksum>
+ <location href="repodata/1f66590abb9d80a053e36fbbcd54e0c7cf69e2253e285598aa402d742302b3e2-other.xml.gz"/>
+ <timestamp>1528467019</timestamp>
+ <size>283</size>
+ <open-size>457</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">4d3534b47120b1d466d207384a419d02f21ae311b83f7fe07aad3e74c453a551</checksum>
+ <open-checksum type="sha256">0f93cde034b3716c4dfc6fb276ef64e8b730362793ab64a3c4e577f99781d075</open-checksum>
+ <location href="repodata/4d3534b47120b1d466d207384a419d02f21ae311b83f7fe07aad3e74c453a551-primary.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>2026</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">92217ee1dd392000dc473547b3dba06cabc8676b2ca10c4ebe242b945c8ea4d2</checksum>
+ <open-checksum type="sha256">7f11cdcd362e4cab36eea20858bd3cbc5221d67443cb7ef3539ef03f30f32cff</open-checksum>
+ <location href="repodata/92217ee1dd392000dc473547b3dba06cabc8676b2ca10c4ebe242b945c8ea4d2-filelists.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>764</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">0b604aa496f768e638dd6f804c33403cf0764fbc4d3cdb41037b9c59f6460e75</checksum>
+ <open-checksum type="sha256">8a248c4e9c66d0e851c96f9fd8bdf1c63fed53e62722bb8a04c628bb82235979</open-checksum>
+ <location href="repodata/0b604aa496f768e638dd6f804c33403cf0764fbc4d3cdb41037b9c59f6460e75-other.sqlite.bz2"/>
+ <timestamp>1528467019</timestamp>
+ <size>736</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">550fd328b5f3aa1366c6bf1d2089f6726eac2efc273fec3e1c9547d0fd272439</checksum>
+ <open-checksum type="sha256">9bf4875009a12466f77d39f1fcd0360c0cf109b2b1a60512a20133b9217cd4a7</open-checksum>
+ <location href="repodata/550fd328b5f3aa1366c6bf1d2089f6726eac2efc273fec3e1c9547d0fd272439-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>269</size>
+ <open-size>471</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.i686
+ - httpd-doc-0:2.4.25-7.i686
+ - libnghttp2-0:1.21.1-1.i686
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467019</revision>
+ <data type="primary">
+ <checksum type="sha256">caf6347c2a45d04a7bb0dbff256380fa1ff7af97d5f27dca09b3e80cd05c57c7</checksum>
+ <open-checksum type="sha256">4fca2f5cbfa6ab7cefe91c28524133f2720f73669be8d47fb3050db18f8c599a</open-checksum>
+ <location href="repodata/caf6347c2a45d04a7bb0dbff256380fa1ff7af97d5f27dca09b3e80cd05c57c7-primary.xml.gz"/>
+ <timestamp>1528467020</timestamp>
+ <size>831</size>
+ <open-size>3352</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">49c3743df58e1b96d8e0101f2acd400e3e0fb727fc2801be142e2abc69ebe30f</checksum>
+ <open-checksum type="sha256">4ce6839566552e66814641338f04803d58950d1e7c463269b930278b43cbdaf0</open-checksum>
+ <location href="repodata/49c3743df58e1b96d8e0101f2acd400e3e0fb727fc2801be142e2abc69ebe30f-filelists.xml.gz"/>
+ <timestamp>1528467020</timestamp>
+ <size>340</size>
+ <open-size>623</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">876456a8161f53035adf586603e355198f241b8de4fcc107895515e223d5d592</checksum>
+ <open-checksum type="sha256">83da2d6a35f13be3a4c34ecbbc1de48ea8c99bedf1e73b962378b5ffac5e8926</open-checksum>
+ <location href="repodata/876456a8161f53035adf586603e355198f241b8de4fcc107895515e223d5d592-other.xml.gz"/>
+ <timestamp>1528467020</timestamp>
+ <size>339</size>
+ <open-size>619</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">ad24e687e4f3af0583f63fcd4f0e1e93b3ec279f011c69c28aca38e742e44f50</checksum>
+ <open-checksum type="sha256">d613a96848dfc08ada6fb0f9dc6c1b4f6f21939ab3a7dd2248b1988654981627</open-checksum>
+ <location href="repodata/ad24e687e4f3af0583f63fcd4f0e1e93b3ec279f011c69c28aca38e742e44f50-primary.sqlite.bz2"/>
+ <timestamp>1528467020</timestamp>
+ <size>2213</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">4bd94b7b17f27a3d6323fcac3e2f8445fb4c8cd3852f9c8e436f031190630ee2</checksum>
+ <open-checksum type="sha256">80c79e50a5de27f5e51e5e831679d7fc6942815e3e95bbdaf2d1a3cd668718ee</open-checksum>
+ <location href="repodata/4bd94b7b17f27a3d6323fcac3e2f8445fb4c8cd3852f9c8e436f031190630ee2-filelists.sqlite.bz2"/>
+ <timestamp>1528467020</timestamp>
+ <size>827</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">8e04d815eaeb276a31beba7b289607497c1d5ada7a89e64fe678249092925310</checksum>
+ <open-checksum type="sha256">1c92e2a8e32a36e2182fd837ea2b01717302815eaaba863a3dc8478612e2afee</open-checksum>
+ <location href="repodata/8e04d815eaeb276a31beba7b289607497c1d5ada7a89e64fe678249092925310-other.sqlite.bz2"/>
+ <timestamp>1528467020</timestamp>
+ <size>795</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">01513c613857f65e208d002e44c245fc9348370d2e230d5a9147859cc2440e3b</checksum>
+ <open-checksum type="sha256">36004e77217e2e7a7082ed5f92a18ab63add84dd6e631754993fe0157e5cbc2a</open-checksum>
+ <location href="repodata/01513c613857f65e208d002e44c245fc9348370d2e230d5a9147859cc2440e3b-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>316</size>
+ <open-size>627</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.s390x
+ - httpd-doc-0:2.4.25-7.s390x
+ - libnghttp2-0:1.21.1-1.s390x
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467021</revision>
+ <data type="primary">
+ <checksum type="sha256">b03ed2bfa70647d3929298055edcd0d3cc70f6c9bb559f02abd197bf4de42cfd</checksum>
+ <open-checksum type="sha256">e0c4bccdb5f7983dcecd7a0c0376a3ee147b0ce8b54a7ec54dcb370c2b7d784a</open-checksum>
+ <location href="repodata/b03ed2bfa70647d3929298055edcd0d3cc70f6c9bb559f02abd197bf4de42cfd-primary.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>832</size>
+ <open-size>3361</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">a56b68690d5c0d9c40a9995cd9faa7dab2c755feda01f3558054dd9a8ac57f96</checksum>
+ <open-checksum type="sha256">4876f0456ef65f04491cb767f220d85b435ac5cbe2794bbddbf81951d5dd0785</open-checksum>
+ <location href="repodata/a56b68690d5c0d9c40a9995cd9faa7dab2c755feda01f3558054dd9a8ac57f96-filelists.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>344</size>
+ <open-size>626</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">819e86e32d196c28ae699db394ad42096e1413f9de33ea048a8cb679f9cb25af</checksum>
+ <open-checksum type="sha256">0d0cadb4298a182fc7a0a44212b5d5606dc5e8327fe4764f87ef1c6c2e87be8c</open-checksum>
+ <location href="repodata/819e86e32d196c28ae699db394ad42096e1413f9de33ea048a8cb679f9cb25af-other.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>343</size>
+ <open-size>622</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">69857c70a6451479ee0c0a0e37286dc00bca5a2faa482d4b1d212eb6136fa0aa</checksum>
+ <open-checksum type="sha256">8f9000bd2a5726ff3db0788652abb24b79159c150fd984409c73c63ac766b4d9</open-checksum>
+ <location href="repodata/69857c70a6451479ee0c0a0e37286dc00bca5a2faa482d4b1d212eb6136fa0aa-primary.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>2215</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">c9e0910dc42a296d290975c711256d8f05e77b7c3784ca995454e4dbf5569652</checksum>
+ <open-checksum type="sha256">bb26665eb001ebeb11fe20f93a666d2401d71ea8ad43e120911b1af4ad567f0e</open-checksum>
+ <location href="repodata/c9e0910dc42a296d290975c711256d8f05e77b7c3784ca995454e4dbf5569652-filelists.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>828</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">90e5b6c7980d346897cdc6ca48d18f1490cbc7b38c6882f0c897e1c2ec2eaa67</checksum>
+ <open-checksum type="sha256">20be4f6b9eb4020ea9f5dad9f5163230fee34d554c80aaa4d78742a6a8628820</open-checksum>
+ <location href="repodata/90e5b6c7980d346897cdc6ca48d18f1490cbc7b38c6882f0c897e1c2ec2eaa67-other.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>805</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">5d551a4c6dbf729c05160bdefb5ed00d26716c69c042cf01aab2565640cb22ac</checksum>
+ <open-checksum type="sha256">f7436f25a9691aa30d5618dda78ebe18cb523080edfbbc987e3154e8e648be30</open-checksum>
+ <location href="repodata/5d551a4c6dbf729c05160bdefb5ed00d26716c69c042cf01aab2565640cb22ac-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>318</size>
+ <open-size>631</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.src
+ - libnghttp2-0:1.21.1-1.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 1
+ context: 3b6beaf8
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-7.x86_64
+ - httpd-doc-0:2.4.25-7.x86_64
+ - libnghttp2-0:1.21.1-1.x86_64
+...
--- /dev/null
+document: modulemd-defaults
+version: 1
+data:
+ module: httpd
+ stream: 2.4
+ profiles:
+ 2.4: [default]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467020</revision>
+ <data type="primary">
+ <checksum type="sha256">c26d28065fddecf2a5ae53dc10a3abe9913a0a8dc5281149038af0809c60f771</checksum>
+ <open-checksum type="sha256">eb626fd349f931342b269a75687afca6b014fd81fb3550a5be6005f90a22dce0</open-checksum>
+ <location href="repodata/c26d28065fddecf2a5ae53dc10a3abe9913a0a8dc5281149038af0809c60f771-primary.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>836</size>
+ <open-size>3364</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">1d9f907984681afe87cf3db455db7e496006d9873e143ce91f57f48163c1242c</checksum>
+ <open-checksum type="sha256">1042270209c355525420b6a558972ae3c46d83179db0cdba480bdd58c294d3b3</open-checksum>
+ <location href="repodata/1d9f907984681afe87cf3db455db7e496006d9873e143ce91f57f48163c1242c-filelists.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>345</size>
+ <open-size>629</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">c5a113dc68969c8ec64fb2417682f442dd61d4befceb8133caa88c1b8332dc6e</checksum>
+ <open-checksum type="sha256">a54d25a79ed74974c8b08c707142de5317c316dea2fef44d7cfa2378e4069e9b</open-checksum>
+ <location href="repodata/c5a113dc68969c8ec64fb2417682f442dd61d4befceb8133caa88c1b8332dc6e-other.xml.gz"/>
+ <timestamp>1528467021</timestamp>
+ <size>345</size>
+ <open-size>625</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">8f9dd5e236731653e5a4487334ddcd48907822e38fd5310e769b4e288cca09b8</checksum>
+ <open-checksum type="sha256">fc781083b417f313dd9d4c37dc992d506a4a08c1ed057fe6f31af6f03d3d64b8</open-checksum>
+ <location href="repodata/8f9dd5e236731653e5a4487334ddcd48907822e38fd5310e769b4e288cca09b8-primary.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>2225</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">7401efdadd4f7177d130643053c50bad88b71c853a5dfaf844f5b1917e529d85</checksum>
+ <open-checksum type="sha256">344b6331e63a1d3542a6040edbba1ae42c8982511228a4a9b102cbaed4e2ff65</open-checksum>
+ <location href="repodata/7401efdadd4f7177d130643053c50bad88b71c853a5dfaf844f5b1917e529d85-filelists.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>816</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">e9ab31d36533c2764cf3d4517296cd078a08744a4d1e277bc312a57e1977959e</checksum>
+ <open-checksum type="sha256">a779d67160cded915493c4ca3a7f91a715f694b39377981c4a3448d43a3470d5</open-checksum>
+ <location href="repodata/e9ab31d36533c2764cf3d4517296cd078a08744a4d1e277bc312a57e1977959e-other.sqlite.bz2"/>
+ <timestamp>1528467021</timestamp>
+ <size>806</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">c737ef5a58c444520311f7471220f60814489e8e0821abebed1c8a3c132eb8a3</checksum>
+ <open-checksum type="sha256">57532accf9153cc4f51ce57a29378622fd23f64f2a4f8ae671b9939e4e75ce6c</open-checksum>
+ <location href="repodata/c737ef5a58c444520311f7471220f60814489e8e0821abebed1c8a3c132eb8a3-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>319</size>
+ <open-size>635</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: i686
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.i686
+ - httpd-doc-0:2.4.25-8.i686
+ - libnghttp2-0:1.21.1-1.i686
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467021</revision>
+ <data type="primary">
+ <checksum type="sha256">6e0ccd539b8487c56b4be9c167dd1d518a8ff7354245f4593e817bfe5909bbc5</checksum>
+ <open-checksum type="sha256">80a9a400378cfbfa3e0d81cc3e0c8a6a3f7207c317eafc4cb453f1ad8730b4f6</open-checksum>
+ <location href="repodata/6e0ccd539b8487c56b4be9c167dd1d518a8ff7354245f4593e817bfe5909bbc5-primary.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>833</size>
+ <open-size>3352</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">e2462308c4477e4740543028b0288c42942cd4984bbb37b95f4ba9794488484f</checksum>
+ <open-checksum type="sha256">be9f281c588f589d100006151e05b68be484a10e95d684d271b4e2631b8bef23</open-checksum>
+ <location href="repodata/e2462308c4477e4740543028b0288c42942cd4984bbb37b95f4ba9794488484f-filelists.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>342</size>
+ <open-size>623</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">0860d05cdbbb821b652fd9f93258913d9c3f200c886612f179c26113a24d5e9d</checksum>
+ <open-checksum type="sha256">715e6e9a23f43d8107205f9964fcdcd9621451033ef2eb0ad70ca5183d31a7f6</open-checksum>
+ <location href="repodata/0860d05cdbbb821b652fd9f93258913d9c3f200c886612f179c26113a24d5e9d-other.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>341</size>
+ <open-size>619</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">4d2cdb7879963dd460741bf32b7d3d1fc6ca38d68ed10f8dc7fbfc3ccc967ef4</checksum>
+ <open-checksum type="sha256">5276bd6df4d9b153c1b0cb64b59e604abcd1313619c641e5bf4857a7fb2daabf</open-checksum>
+ <location href="repodata/4d2cdb7879963dd460741bf32b7d3d1fc6ca38d68ed10f8dc7fbfc3ccc967ef4-primary.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>2204</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">0d39bb01e072e5f21b723a180ee504255efe0f68aae2d1e406858e86af0e188b</checksum>
+ <open-checksum type="sha256">72ce067f4bcb417f1e242d601d239001f0c38d5ba3edc6ade6b73cb03e774066</open-checksum>
+ <location href="repodata/0d39bb01e072e5f21b723a180ee504255efe0f68aae2d1e406858e86af0e188b-filelists.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>816</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">e5cbbe3cdb9ff025a6f1a5c773473494a0ebef4b0b5c96ba5a40da869092af08</checksum>
+ <open-checksum type="sha256">4c4f455aaa66b54ec70dd22d016bbcf50a097d90f96e03a2900fa884bce0dc2c</open-checksum>
+ <location href="repodata/e5cbbe3cdb9ff025a6f1a5c773473494a0ebef4b0b5c96ba5a40da869092af08-other.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>805</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">2b65f2224de8f1e873e2c1c6b6853b0a9b7d3bc6181b6d7be99a7ec1e049ef57</checksum>
+ <open-checksum type="sha256">35e98277cd6fa95cc029816abf6457d540536e43d759240f1e68be31361b31e1</open-checksum>
+ <location href="repodata/2b65f2224de8f1e873e2c1c6b6853b0a9b7d3bc6181b6d7be99a7ec1e049ef57-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>281</size>
+ <open-size>499</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: s390x
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.s390x
+ - httpd-doc-0:2.4.25-8.s390x
+ - libnghttp2-0:1.21.1-1.s390x
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467022</revision>
+ <data type="primary">
+ <checksum type="sha256">6806a2295b024ee97d996690d5b0a1677004ab4a7a6d186a47876a2096f69697</checksum>
+ <open-checksum type="sha256">4c5d15c400150bca36dba259c5cfee2aecb6c6534a5727438ebfbc96765572b5</open-checksum>
+ <location href="repodata/6806a2295b024ee97d996690d5b0a1677004ab4a7a6d186a47876a2096f69697-primary.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>834</size>
+ <open-size>3361</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">c04af70f97b52b59d2cf36632065217e804650a9e5e2f5dcfdd601ede350b702</checksum>
+ <open-checksum type="sha256">4b09591a99d74bc5fcbfd22321517dbf2f6801dc5a6e7ab177e7810e09f462b3</open-checksum>
+ <location href="repodata/c04af70f97b52b59d2cf36632065217e804650a9e5e2f5dcfdd601ede350b702-filelists.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>341</size>
+ <open-size>626</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">8aee83183505d5a433e991b9db12b46b046686c1ec8552bbe19de8da7f5ed4d2</checksum>
+ <open-checksum type="sha256">9e84851c5a65e877960b1c32ef7e4dd73570682df180608379e93252b970715d</open-checksum>
+ <location href="repodata/8aee83183505d5a433e991b9db12b46b046686c1ec8552bbe19de8da7f5ed4d2-other.xml.gz"/>
+ <timestamp>1528467023</timestamp>
+ <size>342</size>
+ <open-size>622</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">f6e9e967618ffc1bd9c7f9ec0a03d4824254bb351aa4c53657ef28a6f7cb9c77</checksum>
+ <open-checksum type="sha256">30c9c696a56d140755f825b486953256b5baf03bc14b6c984a3d3db7f0ef29bb</open-checksum>
+ <location href="repodata/f6e9e967618ffc1bd9c7f9ec0a03d4824254bb351aa4c53657ef28a6f7cb9c77-primary.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>2206</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">2db9ffba74a218518e2f56343ae309fef90750996929790ed5f07da544d25e72</checksum>
+ <open-checksum type="sha256">167bb07a5773423a5a0576ddc15c94f9ae21e671072126af4bed1db5090d16b2</open-checksum>
+ <location href="repodata/2db9ffba74a218518e2f56343ae309fef90750996929790ed5f07da544d25e72-filelists.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>829</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">222784064998192225948bd42cfd4f309607ed2e956f35e853ec04f6b5bfff26</checksum>
+ <open-checksum type="sha256">03d249591adb911e66b85e16e590aa8e92de44c0771c26ed13a88cf814dc0d61</open-checksum>
+ <location href="repodata/222784064998192225948bd42cfd4f309607ed2e956f35e853ec04f6b5bfff26-other.sqlite.bz2"/>
+ <timestamp>1528467023</timestamp>
+ <size>816</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">43bd4784f0153369535272c70684af4380ae4c54066f0fde2ee346339c6f28e8</checksum>
+ <open-checksum type="sha256">a6025cdd3cd10fe075e2cdd4daaa60c63eaac68c256bb879e24e09ba243bd71e</open-checksum>
+ <location href="repodata/43bd4784f0153369535272c70684af4380ae4c54066f0fde2ee346339c6f28e8-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>283</size>
+ <open-size>503</open-size>
+ </data>
+</repomd>
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: src
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.src
+ - libnghttp2-0:1.21.1-1.src
+...
--- /dev/null
+---
+document: modulemd
+version: 2
+data:
+ name: httpd
+ stream: 2.4
+ version: 2
+ context: 3b6beaf8
+ arch: x86_64
+ summary: Fake module
+ description: >-
+ Fake module
+ license:
+ module:
+ - LGPLv2
+ dependencies:
+ - requires:
+ base-runtime: [f26]
+ profiles:
+ default:
+ rpms:
+ - httpd
+ doc:
+ rpms:
+ - httpd-doc
+ buildopts:
+ rpms: {}
+ artifacts:
+ rpms:
+ - httpd-0:2.4.25-8.x86_64
+ - httpd-doc-0:2.4.25-8.x86_64
+ - libnghttp2-0:1.21.1-1.x86_64
+...
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
+ <revision>1528467022</revision>
+ <data type="primary">
+ <checksum type="sha256">6774c709909c85579b646dad8422b8a62fc4a4d3630d2c76944abb2f045e0b4c</checksum>
+ <open-checksum type="sha256">93995f27eb7aed89f1ff4861408b7934f8869934530f11d71fd483e33a5b25db</open-checksum>
+ <location href="repodata/6774c709909c85579b646dad8422b8a62fc4a4d3630d2c76944abb2f045e0b4c-primary.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>837</size>
+ <open-size>3364</open-size>
+ </data>
+ <data type="filelists">
+ <checksum type="sha256">c3d8bd9d381397223a8b957d3813fbdeb3c700b6937a347dfbc90dbb0492640f</checksum>
+ <open-checksum type="sha256">eae6920641e178c009b7fb16f9d9559dc2a230569fff808ebf3fac274060d4b7</open-checksum>
+ <location href="repodata/c3d8bd9d381397223a8b957d3813fbdeb3c700b6937a347dfbc90dbb0492640f-filelists.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>341</size>
+ <open-size>629</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">143f547f02063d5221cc099f8fe693e9abf3456fdf3d4afe5f95b1cf81403d9d</checksum>
+ <open-checksum type="sha256">d31d06936f529a9fb9912d3168c1cdaf3b39b376e0c1e612cb70adb20df7b35d</open-checksum>
+ <location href="repodata/143f547f02063d5221cc099f8fe693e9abf3456fdf3d4afe5f95b1cf81403d9d-other.xml.gz"/>
+ <timestamp>1528467022</timestamp>
+ <size>341</size>
+ <open-size>625</open-size>
+ </data>
+ <data type="primary_db">
+ <checksum type="sha256">38229572e59980be53dc8b9d3741e2b46877b3ce7a049f968066c1eca0757dff</checksum>
+ <open-checksum type="sha256">33a821c29a3c09375356a9a761995c7b13bed4872b63f4e9d4a7510f22bb40b4</open-checksum>
+ <location href="repodata/38229572e59980be53dc8b9d3741e2b46877b3ce7a049f968066c1eca0757dff-primary.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>2216</size>
+ <open-size>106496</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="filelists_db">
+ <checksum type="sha256">8bab2a03f45ea12b1612b5fecdc6137cf69412d5810cebe1620d90eb2e562f8f</checksum>
+ <open-checksum type="sha256">e56d0f881b9392d93e39c93fc1187914f4e9b87262342ab6471d1f0d7a671a76</open-checksum>
+ <location href="repodata/8bab2a03f45ea12b1612b5fecdc6137cf69412d5810cebe1620d90eb2e562f8f-filelists.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>829</size>
+ <open-size>28672</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="other_db">
+ <checksum type="sha256">cb63c3e8e5fc7fc855701a2b1d78c54ca76932fc3ace708a2212d527ce2aba90</checksum>
+ <open-checksum type="sha256">be8fa87ffd184f35da5de60d2cd01f5b4034b461d441a13e623ab7a4ccc9d65a</open-checksum>
+ <location href="repodata/cb63c3e8e5fc7fc855701a2b1d78c54ca76932fc3ace708a2212d527ce2aba90-other.sqlite.bz2"/>
+ <timestamp>1528467022</timestamp>
+ <size>814</size>
+ <open-size>24576</open-size>
+ <database_version>10</database_version>
+ </data>
+ <data type="modules">
+ <checksum type="sha256">62ed5cb5877c1995260ea3deeaf517c1335d41a26fa56bbf791e0b8848debf57</checksum>
+ <open-checksum type="sha256">31c281474f93b893c9f365b435d1929fb2fb1c99c2646cb6732bd97b14984b3c</open-checksum>
+ <location href="repodata/62ed5cb5877c1995260ea3deeaf517c1335d41a26fa56bbf791e0b8848debf57-modules.yaml.gz"/>
+ <timestamp>1531828717</timestamp>
+ <size>284</size>
+ <open-size>507</open-size>
+ </data>
+</repomd>
--- /dev/null
+#!/usr/bin/python
+
+
+import os
+import json
+import hashlib
+
+import gi
+
+gi.require_version('Modulemd', '1.0')
+from gi.repository import Modulemd
+
+MODULES_DIR = os.path.join(os.path.dirname(__file__), "..", "modules")
+SPECS_DIR = os.path.join(os.path.dirname(__file__), "..", "specs")
+
+
+def parse_module_id(module_id):
+ return module_id.rsplit("-", 2)
+
+
+for module_id in os.listdir(MODULES_DIR):
+ if module_id.startswith("_"):
+ continue
+
+ name, stream, version = parse_module_id(module_id)
+
+ profiles_file = os.path.join(SPECS_DIR, module_id, "profiles.json")
+ if os.path.isfile(profiles_file):
+ with open(profiles_file, "r") as f:
+ profiles = json.load(f)
+ else:
+ profiles = {}
+
+ for arch in os.listdir(os.path.join(MODULES_DIR, module_id)):
+ if arch == "noarch":
+ continue
+
+ module_dir = os.path.join(MODULES_DIR, module_id, arch)
+ rpms = [i for i in os.listdir(module_dir) if i.endswith(".rpm")]
+
+ noarch_module_dir = os.path.join(MODULES_DIR, module_id, "noarch")
+ if os.path.isdir(noarch_module_dir):
+ noarch_rpms = [i for i in os.listdir(noarch_module_dir) if i.endswith(".rpm")]
+ else:
+ noarch_rpms = []
+
+ rpms = sorted(set(rpms) | set(noarch_rpms))
+
+ # HACK: force epoch to make test data compatible with libmodulemd >= 1.4.0
+ rpms_with_epoch = []
+ for i in rpms:
+ n, v, ra = i.rsplit("-", 2)
+ nevra = "%s-0:%s-%s" % (n, v, ra)
+ rpms_with_epoch.append(nevra)
+ rpms = rpms_with_epoch
+
+ mmd = Modulemd.Module()
+ mmd.set_mdversion(int(2))
+ mmd.set_name(name)
+ mmd.set_stream(stream)
+ mmd.set_version(int(version))
+ # context is set later, computed from runtime deps
+ mmd.set_arch(arch)
+ sset = Modulemd.SimpleSet()
+ sset.add("LGPLv2")
+ mmd.set_module_licenses(sset)
+ mmd.set_summary("Fake module")
+ mmd.set_description(mmd.get_summary())
+ artifacts = Modulemd.SimpleSet()
+ for rpm in rpms:
+ #mmd.add_module_component(rpm.rsplit("-", 2)[0], "")
+ artifacts.add(rpm[:-4])
+ mmd.set_rpm_artifacts(artifacts)
+ for profile_name in profiles:
+ profile = Modulemd.Profile()
+ profile.set_name(profile_name)
+ profile_rpms = Modulemd.SimpleSet()
+ profile_rpms.set(profiles[profile_name]["rpms"])
+ profile.set_rpms(profile_rpms)
+ mmd.add_profile(profile)
+
+ if name == "httpd":
+ dependencies = Modulemd.Dependencies()
+ if stream == "2.4":
+ dependencies.add_requires_single("base-runtime", "f26")
+ elif stream == "2.2":
+ dependencies.add_requires("base-runtime", [])
+ mmd.add_dependencies(dependencies)
+
+ # iterate through all deps and create context hash in a repeatable manner
+ context_hash = hashlib.sha256()
+ for dependencies in mmd.peek_dependencies():
+ for dep_name, dep_streams in dependencies.peek_requires().items():
+ if dep_streams:
+ for dep_stream in dep_streams.get():
+ context_hash.update("%s:%s" % (dep_name, dep_stream))
+ else:
+ context_hash.update(dep_name)
+ mmd.set_context(context_hash.hexdigest()[:8])
+
+ Modulemd.dump([mmd], os.path.join(module_dir, "%s.%s.yaml" % (module_id, arch)))
--- /dev/null
+#!/usr/bin/python
+
+
+import os
+import argparse
+import subprocess
+import tempfile
+
+import gi
+gi.require_version('Modulemd', '1.0')
+from gi.repository import Modulemd
+
+
+def get_parser():
+ """
+ Construct argument parser.
+
+ :returns: ArgumentParser object with arguments set up.
+ :rtype: argparse.ArgumentParser
+ """
+ parser = argparse.ArgumentParser(
+ description="Scan directory for modulemd yaml files and inject them into repodata.",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ )
+ parser.add_argument(
+ "path",
+ metavar="directory_to_index",
+ )
+ return parser
+
+
+def index_modulemd_files(repo_path):
+ result = []
+ for fn in sorted(os.listdir(repo_path)):
+ if not fn.endswith(".yaml"):
+ continue
+ yaml_path = os.path.join(repo_path, fn)
+ mmd = Modulemd.objects_from_file_ext(yaml_path)
+ result.append(mmd[0][0])
+ return result
+
+
+def modify_repo(repo_path, modules):
+ tmp = tempfile.mkdtemp()
+ path = os.path.join(tmp, "modules.yaml")
+ for module in modules:
+ Modulemd.dump(modules, path)
+ subprocess.check_call(["modifyrepo_c", "--mdtype=modules", path,
+ os.path.join(repo_path, "repodata")])
+ os.unlink(path)
+ os.rmdir(tmp)
+
+
+if __name__ == "__main__":
+ parser = get_parser()
+ args = parser.parse_args()
+
+ modules = index_modulemd_files(args.path)
+ modify_repo(args.path, modules)
--- /dev/null
+Name: grub2
+Version: 2.02
+Release: 0.40
+License: LGPLv2
+Summary: Fake package
+
+Requires: filesystem
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+Name: httpd-provides-name-version-release
+Version: 3.0
+Release: 1
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+
+Provides: httpd = %{version}-%{release}
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+Name: httpd-provides-name
+Version: 3.0
+Release: 1
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+
+Provides: httpd
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+Name: httpd
+Version: 2.2.10
+Release: 1
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+Name: libnghttp2
+Version: 1.21.1
+Release: 1.1
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+
+
+%changelog
--- /dev/null
+Name: basesystem
+Version: 11
+Release: 3
+License: LGPLv2
+Summary: Fake package
+
+Requires: filesystem
+
+BuildArch: noarch
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+Name: bash
+Version: 4.4.12
+Release: 2
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+%if %__isa_bits == 32
+Requires: libpthread.so.0(GLIBC_2.0)
+%else
+Requires: libpthread.so.0(GLIBC_2.3)(64bit)
+%endif
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+BuildArch: noarch
+Requires: %{name}
+
+%description doc
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+Name: filesystem
+Version: 3.2
+Release: 40
+License: LGPLv2
+Summary: Fake package
+
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+Name: glibc
+Version: 2.25
+Release: 4
+License: LGPLv2
+Summary: Fake package
+
+Requires: %{name}-common = %{version}-%{release}
+Requires: basesystem
+%if %__isa_bits == 32
+Provides: libc.so.6()
+Provides: libpthread.so.0(GLIBC_2.0)
+%else
+Provides: libc.so.6()(64bit)
+Provides: libpthread.so.0(GLIBC_2.3)(64bit)
+%endif
+
+%description
+Fake package
+
+%package common
+Summary: Fake package
+
+%description common
+Fake package
+
+%package -n dummy-nscd
+Summary: Fake package
+
+%description -n dummy-nscd
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+%package debuginfo-common
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo-common
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%if %__isa_bits == 32
+%ghost /usr/lib/libc.so.6
+%else
+%ghost /usr/lib64/libc.so.6
+%endif
+
+%files common
+%files -n dummy-nscd
+%files debuginfo
+%files debuginfo-common
+
+
+%changelog
--- /dev/null
+Name: kernel
+Version: 4.11.0
+Release: 1
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+%package headers
+Summary: Fake package
+
+%description headers
+Fake package
+
+%package doc
+Summary: Fake package
+BuildArch: noarch
+
+%description doc
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files headers
+%files doc
+
+
+%changelog
--- /dev/null
+{
+ "minimal": {
+ "rpms": ["glibc"]
+ },
+ "default": {
+ "rpms": ["glibc", "bash", "systemd", "kernel"]
+ }
+}
\ No newline at end of file
--- /dev/null
+Name: systemd
+Version: 233
+Release: 3
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+../base-runtime-f26-1/basesystem.spec
\ No newline at end of file
--- /dev/null
+../base-runtime-f26-1/bash.spec
\ No newline at end of file
--- /dev/null
+../base-runtime-f26-1/filesystem.spec
\ No newline at end of file
--- /dev/null
+Name: glibc
+Version: 2.25.90
+Release: 2
+License: LGPLv2
+Summary: Fake package
+
+Requires: %{name}-common = %{version}-%{release}
+Requires: basesystem
+%if %__isa_bits == 32
+Provides: libc.so.6()
+Provides: libpthread.so.0(GLIBC_2.0)
+%else
+Provides: libc.so.6()(64bit)
+Provides: libpthread.so.0(GLIBC_2.3)(64bit)
+%endif
+
+%description
+Fake package
+
+%package common
+Summary: Fake package
+
+%description common
+Fake package
+
+%package -n dummy-nscd
+Summary: Fake package
+
+%description -n dummy-nscd
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+%package debuginfo-common
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo-common
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%if %__isa_bits == 32
+%ghost /usr/lib/libc.so.6
+%else
+%ghost /usr/lib64/libc.so.6
+%endif
+
+%files common
+%files -n dummy-nscd
+%files debuginfo
+%files debuginfo-common
+
+
+%changelog
--- /dev/null
+../base-runtime-f26-1/kernel.spec
\ No newline at end of file
--- /dev/null
+../base-runtime-f26-1/profiles.json
\ No newline at end of file
--- /dev/null
+../base-runtime-f26-1/systemd.spec
\ No newline at end of file
--- /dev/null
+Name: basesystem
+Version: 10.0
+Release: 7
+License: LGPLv2
+Summary: Fake package
+
+Requires: filesystem
+
+BuildArch: noarch
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+Name: bash
+Version: 4.2.46
+Release: 21
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+%if %__isa_bits == 32
+Requires: libpthread.so.0(GLIBC_2.0)
+%else
+Requires: libpthread.so.0(GLIBC_2.3)(64bit)
+%endif
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+BuildArch: noarch
+Requires: %{name}
+
+%description doc
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+Name: filesystem
+Version: 3.2
+Release: 21
+License: LGPLv2
+Summary: Fake package
+
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+Name: glibc
+Version: 2.17
+Release: 157
+License: LGPLv2
+Summary: Fake package
+
+Requires: %{name}-common = %{version}-%{release}
+Requires: basesystem
+%if %__isa_bits == 32
+Provides: libc.so.6()
+Provides: libpthread.so.0(GLIBC_2.0)
+%else
+Provides: libc.so.6()(64bit)
+Provides: libpthread.so.0(GLIBC_2.3)(64bit)
+%endif
+
+%description
+Fake package
+
+%package common
+Summary: Fake package
+
+%description common
+Fake package
+
+%package -n dummy-nscd
+Summary: Fake package
+
+%description -n dummy-nscd
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+%package debuginfo-common
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo-common
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%if %__isa_bits == 32
+%ghost /usr/lib/libc.so.6
+%else
+%ghost /usr/lib64/libc.so.6
+%endif
+
+%files common
+%files -n dummy-nscd
+%files debuginfo
+%files debuginfo-common
+
+
+%changelog
--- /dev/null
+Name: kernel
+Version: 3.10.0
+Release: 514
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+%package headers
+Summary: Fake package
+
+%description headers
+Fake package
+
+%package doc
+Summary: Fake package
+BuildArch: noarch
+
+%description doc
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files headers
+%files doc
+
+
+%changelog
--- /dev/null
+../base-runtime-f26-1/profiles.json
\ No newline at end of file
--- /dev/null
+Name: systemd
+Version: 219
+Release: 30
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+
+
+%changelog
--- /dev/null
+#!/bin/bash
+
+
+# run this script to (re-)generate module repos
+
+
+# Requirements:
+# * createrepo_c
+# * rpmbuild
+
+
+export LC_ALL=C
+
+set -e
+
+
+DIR=$(dirname $(readlink -f $0))
+ARCHES="i686 x86_64 s390x"
+
+
+./_create_modulemd.py
+
+
+for target in $ARCHES; do
+ cp ../defaults/httpd.yaml ../modules/httpd-2.4-1/$target/
+done
+
+for module in $DIR/*-*-* $DIR/_non-modular; do
+ module_name=$(basename $module)
+ for target in $ARCHES; do
+ repo_path=$DIR/../modules/$module_name/$target
+ repo_path_all=$DIR/../modules/_all/$target
+
+ mkdir -p $repo_path_all
+ cp $repo_path/* $repo_path_all/ || :
+
+ createrepo_c $repo_path
+ if [ "_non-modular" != "$module_name" ]
+ then
+ ./_createrepo_c_modularity_hack.py $repo_path
+ fi
+ done
+done
+
+
+for target in $ARCHES; do
+ repo_path=$DIR/../modules/_all/$target
+ createrepo_c $repo_path
+ ./_createrepo_c_modularity_hack.py $repo_path
+done
+
+
+echo "DONE: Test data created"
--- /dev/null
+Name: httpd
+Version: 2.2.15
+Release: 59
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+%files doc
+
+
+%changelog
--- /dev/null
+{
+ "default": {
+ "rpms": ["httpd"]
+ },
+ "doc": {
+ "rpms": ["httpd-doc"]
+ }
+}
\ No newline at end of file
--- /dev/null
+Name: httpd
+Version: 2.4.25
+Release: 7
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+Requires: libnghttp2
+
+%description
+Fake package
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files doc
+%files debuginfo
+
+
+%changelog
--- /dev/null
+Name: libnghttp2
+Version: 1.21.1
+Release: 1
+License: LGPLv2
+Summary: Fake package
+
+%description
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files debuginfo
+
+
+%changelog
--- /dev/null
+../httpd-2.2-1/profiles.json
\ No newline at end of file
--- /dev/null
+Name: httpd
+Version: 2.4.25
+Release: 8
+License: LGPLv2
+Summary: Fake package
+
+Requires: glibc
+Requires: libnghttp2
+
+%description
+Fake package
+
+%package doc
+Summary: Fake package
+
+%description doc
+Fake package
+
+%package debuginfo
+Summary: Fake package
+Group: Development/Debug
+
+%description debuginfo
+Fake package
+
+
+#%prep
+#%setup -q
+
+
+%build
+echo OK
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%files doc
+%files debuginfo
+
+
+%changelog
--- /dev/null
+../httpd-2.4-1/libnghttp2.spec
\ No newline at end of file
--- /dev/null
+../httpd-2.2-1/profiles.json
\ No newline at end of file
--- /dev/null
+[test]
+name=Test
+baseurl=file://@CMAKE_SOURCE_DIR@/data/tests/modules/modules/_all/x86_64/
+enabled=1
+gpgcheck=0
+metadata_expire=0
--- /dev/null
+[bumblebee]
+name=bumblebee for fedora Linux $releasever - $basearch - Base
+baseurl=
+ http://install.linux.ncsu.edu/pub/yum/itecs/public/bumblebee/fedora$releasever/
+failovermethod=priority
+enabled=1
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-bumblebeepublic
+
+[bumblebee-source]
+name=bumblebee for fedora Linux $releasever - $basearch - Source
+baseurl=
+ http://install.linux.ncsu.edu/pub/yum/itecs/public/bumblebee/fedora$releasever/SRPMS
+failovermethod=priority
+enabled=0
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-bumblebeepublic
+gpgcheck=1
+
--- /dev/null
+[local]
+name=Local
+baseurl=file:///tmp/repo
+enabled=1
+gpgcheck=0
+metadata_expire=1d
--- /dev/null
+[redhat]
+name=Red Hat
+baseurl=http://www.redhat.com/
+enabled=0
+gpgcheck=0
--- /dev/null
+[whitespace]
+name=repo file with whitespace at the end
+baseurl=http://whitespace
+enabled=1
+gpgcheck=0
+
+
+
+
--- /dev/null
+# html and man documentation are separate targets, apparently there's no way to
+# tell sphinx-build to do them both in one go:
+
+
+if (WITH_HTML OR WITH_MAN)
+ find_program(SPHINX_PROGRAM NAMES "sphinx-build-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
+ if(NOT EXISTS ${SPHINX_PROGRAM})
+ find_program(SPHINX_PROGRAM NAMES sphinx-build-${PYTHON_VERSION_MAJOR})
+ endif()
+ if(NOT EXISTS ${SPHINX_PROGRAM})
+ find_program(SPHINX_PROGRAM NAMES sphinx-build)
+ endif()
+ if(NOT EXISTS ${SPHINX_PROGRAM})
+ message(FATAL_ERROR "Sphinx program not found." )
+ endif()
+endif()
+
+if(WITH_HTML)
+ add_custom_target(doc-html
+ PYTHONPATH=${CMAKE_BINARY_DIR}/src/python ${SPHINX_PROGRAM} -b html
+ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/html
+ COMMENT "Building html documentation"
+ )
+endif()
+if(WITH_MAN)
+ add_custom_target(doc-man ALL
+ PYTHONPATH=${CMAKE_BINARY_DIR}/src/python ${SPHINX_PROGRAM} -b man
+ ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/man
+ COMMENT "Building manpage documentation"
+ )
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/hawkey.3 DESTINATION share/man/man3)
+endif()
--- /dev/null
+..
+ Copyright (C) 2014-2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+*************
+ API Changes
+*************
+
+.. contents::
+
+Introduction
+============
+
+This document describes the API changes the library users should be aware of before upgrading to each respective version. It is our plan to have the amount of changes requiring changing the client code go to a minimum after the library hits the 1.0.0 version.
+
+Depracated API items (classes, methods, etc.) are designated as such in this document. The first release where support for such items can be dropped entirely must be issued at *least five months* after the issue of the release that announced the deprecation and at the same time have, relatively to the deprecating release, either:
+
+* a higher major version number, or
+* a higher minor version number, or
+* a patchlevel number that is *by at least five* greater.
+
+These criteria are likely to tighten in the future as hawkey matures.
+
+Actual changes in the API are then announced in this document as well. ABI changes including changes in functions' parameter counts or types or removal of public symbols from ``libhawkey`` imply an increase in the library's SONAME version.
+
+
+Changes in 0.2.10
+=================
+
+Python bindings
+---------------
+
+:meth:`Query.filter` now returns a new instance of :class:`Query`, the same as
+the original with the new filtering applied. This allows for greater flexibility
+handling the :class:`Query` objects and resembles the way ``QuerySets`` behave in
+Django.
+
+In practice the following code will stop working as expected::
+
+ q = hawkey.Query(self.sack)
+ q.filter(name__eq="flying")
+ # processing the query ...
+
+It needs to be changed to::
+
+ q = hawkey.Query(self.sack)
+ q = q.filter(name__eq="flying")
+ # processing the query ...
+
+The original semantics is now available via the :meth:`Query.filterm` method, so
+the following will also work::
+
+ q = hawkey.Query(self.sack)
+ q.filterm(name__eq="flying")
+ # processing the query ...
+
+Changes in 0.2.11
+=================
+
+Python bindings
+---------------
+
+In Python's :class:`Package` instances accessors for string attributes now
+return None instead of the empty string if the attribute is missing (for instance
+a ``pkg.sourcerpm`` now returns None if ``pkg`` is a source rpm package
+already).
+
+This change is towards a more conventional Python practice. Also, this leaves the
+empty string return value free to be used when it is actually the case.
+
+Changes in 0.3.0
+================
+
+Core
+----
+
+Query: key for reponame filtering
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Query key value used for filtering by the repo name is ``HY_PKG_REPONAME``
+now (was ``HY_PKG_REPO``). The old value was misleading.
+
+Repo initialization
+^^^^^^^^^^^^^^^^^^^
+
+``hy_repo_create()`` for Repo object initialization now needs to be passed a
+name of the repository.
+
+.. _changes_query_installs:
+
+Query installs obsoleted
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+All Goal methods accepting Query as the means of selecting packages, such as
+``hy_goal_install_query()`` have been replaced with their Selector
+counterparts. Selector structures have been introduced for the particular
+purpose of specifying a package that best matches the given criteria and at the
+same time is suitable for installation. For a discussion of this decision see
+:ref:`rationale_selectors`.
+
+
+Python bindings
+---------------
+
+Query: filtering by repository with the reponame key
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Similar change happened in Python, the following constructs::
+
+ q = q.filter(repo="updates")
+
+need to be changed to::
+
+ q = q.filter(reponame="updates")
+
+The old version of this didn't allow using the same string to both construct the
+query and dynamically get the reponame attribute from the returned packages
+(used e.g. in DNF to search by user-specified criteria).
+
+Package: removed methods for direct EVR comparison
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following will no longer work::
+
+ if pkg.evr_eq(some_other_pkg):
+ ...
+
+Instead use the result of ``pkg.evr_cmp``, for instance::
+
+ if pkg.evr_cmp(some_other_pkg) == 0:
+ ...
+
+This function compares only the EVR part of a package, not the name. Since it
+rarely make sense to compare versions of packages of different names, the
+following is suggested::
+
+ if pkg == some_other_pkg:
+ ...
+
+Repo initialization
+^^^^^^^^^^^^^^^^^^^
+
+All instantiations of :class:`hawkey.Repo` now must be given the name of the
+Repo. The following will now fail::
+
+ r = hawkey.Repo()
+ r.name = "fedora"
+
+Use this instead::
+
+ r = hawkey.Repo("fedora")
+
+Query installs obsoleted
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+See :ref:`changes_query_installs` in the C section. In Python Queries will no
+longer work as goal target specifiers, the following will fail::
+
+ q = hawkey.Query(sack)
+ q.filter(name="gimp")
+ goal.install(query=q)
+
+Instead use::
+
+ sltr = hawkey.Selector(sack)
+ sltr.set(name="gimp")
+ goal.install(select=sltr)
+
+Or a convenience notation::
+
+ goal.install(name="gimp")
+
+Changes in 0.3.1
+================
+
+Query: ``hy_query_filter_package_in()`` takes a new parameter
+-------------------------------------------------------------
+
+``keyname`` parameter was added to the function signature. The new parameter
+allows filtering by a specific relation to the resulting packages, for
+instance::
+
+ hy_query_filter_package_in(q, HY_PKG_OBSOLETES, HY_EQ, pset)
+
+only leaves the packages obsoleting a package in ``pset`` a part of the result.
+
+Removed ``hy_query_filter_obsoleting()``
+----------------------------------------
+
+The new version of ``hy_query_filter_package_in()`` handles this now, see above.
+
+In Python, the following is no longer supported::
+
+ q = query.filter(obsoleting=1)
+
+The equivalent new syntax is::
+
+ installed = hawkey.Query(sack).filter(reponame=SYSTEM_REPO_NAME)
+ q = query.filter(obsoletes=installed)
+
+Changes in 0.3.2
+================
+
+Removed ``hy_packagelist_of_obsoletes``.
+----------------------------------------
+
+The function was not systematic. Same result is achieved by obtaining obsoleting
+reldeps from a package and then trying to find the installed packages that
+provide it. In Python::
+
+ q = hawkey.Query(sack).filter(reponame=SYSTEM_REPO_NAME, provides=pkg.obsoletes)
+
+Changes in 0.3.3
+================
+
+Renamed ``hy_package_get_nvra`` to ``hy_package_get_nevra``
+-----------------------------------------------------------
+
+The old name was by error, the functionality has not changed: this function has
+always returned the full NEVRA, skipping the epoch part when it's 0.
+
+Changes in 0.3.4
+================
+
+Python bindings
+---------------
+
+``pkg.__repr__()`` is more verbose now
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Previously, ``repr(pkg)`` would yield for instance ``<_hawkey.Package object,
+id: 5>``. Now more complete information is present, including the package's
+NEVRA and repository: ``<hawkey.Package object id 5, foo-2-9\.noarch,
+@System>``.
+
+Also notice that the representation now mentions the final ``hawkey.Package``
+type, not ``_hawkey.Package``. Note that these are currently the same.
+
+Changes in 0.3.8
+================
+
+Core
+----
+
+New parameter ``rootdir`` to ``hy_sack_create()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``hy_sack_create()`` now accepts third argument, ``rootdir``. This can be used
+to tell Hawkey that we are intending to do transactions in a changeroot, not in
+the current root. It effectively makes use of the RPM database found under
+``rootdir``. To make your code compile in 0.3.8 without changing functionality, change::
+
+ HySack sack = hy_sack_create(cachedir, arch);
+
+to::
+
+ HySack sack = hy_sack_create(cachedir, arch, NULL);
+
+Python bindings
+---------------
+
+Forms recognized by ``Subject`` are no longer an instance-scope setting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It became necessary to differentiate between the default forms used by
+``subject.nevra_possibilities()`` and
+``subject.nevra_possibilities_real()``. Therefore there is little sense in
+setting the default form for an entire ``Subject`` instance. The following
+code::
+
+ subj = hawkey.Subject("input", form=hawkey.FORM_NEVRA)
+ result = list(subj.nevra_possibilities())
+
+is thus replaced by::
+
+ subj = hawkey.Subject("input")
+ result = list(subj.nevra_possibilities(form=hawkey.FORM_NEVRA))
+
+Changes in 0.3.9
+================
+
+Core
+----
+
+Flags for ``hy_sack_create``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``hy_sack_create()`` now accepts fourth argument, ``flags``, introduced to
+modify the sack behavior with boolean flags. Currently only one flag is
+supported, ``HY_MAKE_CACHE_DIR``, which causes the cache directory to be created
+if it doesn't exist yet. To preserve the previous behavior, change the
+following::
+
+ HySack sack = hy_sack_create(cachedir, arch, rootdir);
+
+into::
+
+ HySack sack = hy_sack_create(cachedir, arch, rootdir, HY_MAKE_CACHE_DIR);
+
+``hy_sack_get_cache_path`` is renamed to ``hy_sack_get_cache_dir``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Update your code by mechanically replacing the name.
+
+
+Python bindings
+---------------
+
+``make_cache_dir`` for Sack's constructor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A new sack by default no longer automatically creates the cache directory. To
+get the old behavior, append ``make_cache_dir=True`` to the
+:meth:`.Sack.__init__` arguments, that is change the following::
+
+ sack = hawkey.Sack(...)
+
+to::
+
+ sack = hawkey.Sack(..., make_cache_dir=True)
+
+
+``cache_path`` property of ``Sack`` renamed to ``cache_dir``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Reflects the similar change in C API.
+
+Changes in 0.3.11
+=================
+
+.. _0_3_11_core-label:
+
+Core
+----
+
+``hy_goal_package_obsoletes()`` removed, ``hy_goal_list_obsoleted_by_package()`` provided instead
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``hy_goal_package_obsoletes()`` was flawed in that it only returned a single
+obsoleted package (in general, package can obsolete arbitrary number of packages
+and upgrade a package of the same name which is also reported as an
+obsolete). Use ``hy_goal_list_obsoleted_by_package()`` instead, to see the
+complete set of packages that inclusion of the given package in an RPM
+transaction will cause to be removed.
+
+``hy_goal_list_erasures()`` does not report obsoletes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In other words, ``hy_goal_list_erasures()`` and ``hy_goal_list_obsoleted()``
+return disjoint sets.
+
+
+Python bindings
+---------------
+
+Directly reflecting the :ref:`core changes <0_3_11_core-label>`. In particular,
+instead of::
+
+ obsoleted_pkg = goal.package_obsoletes(pkg)
+
+use::
+
+ obsoleted = goal.obsoleted_by_package(pkg) # list
+ obsoleted_pkg = obsoleted[0]
+
+Changes in 0.4.5
+=================
+
+Core
+----
+
+Query: ``hy_query_filter_latest()`` now filter latest packages ignoring architecture
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For old function behavior use new function ``hy_query_filter_latest_per_arch()``
+
+Python bindings
+---------------
+
+In Python's :class:`Query` option ``latest`` in :meth:`Query.filter` now filter
+only the latest packages ignoring architecture. The original semantics for filtering
+latest packages for each arch is now available via ``latest_per_arch`` option.
+
+For example there are these packages in sack::
+
+ glibc-2.17-4.fc19.x86_64
+ glibc-2.16-24.fc18.x86_64
+ glibc-2.16-24.fc18.i686
+
+ >>> q = hawkey.Query(self.sack).filter(name="glibc")
+ >>> map(str, q.filter(latest=True))
+ ['glibc-2.17-4.fc19.x86_64']
+
+ >>> map(str, q.filter(latest_per_arch=True))
+ ['glibc-2.17-4.fc19.x86_64', 'glibc-2.16-24.fc18.i686']
+
+Changes in 0.4.13
+=================
+
+Core
+----
+
+Deprecated ``hy_package_get_update_*``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The functions were deprecated because there can be multiple advisories referring
+to a single package. Please use the new function ``hy_package_get_advisories()``
+which returns all these advisories. New functions ``hy_advisory_get_*`` provide
+the data retrieved by the deprecated functions.
+
+The only exception is the ``hy_package_get_update_severity()`` which will be
+dropped without any replacement. However advisory types and severity levels are
+distinguished from now and the type is accessible via ``hy_advisory_get_type()``.
+Thus enum ``HyUpdateSeverity`` was also deprecated. A new ``HyAdvisoryType``
+should be used instead.
+
+The old functions will be dropped after 2014-07-07.
+
+Changes in 0.4.15
+=================
+
+.. _0_4_15_core-label:
+
+Core
+----
+
+``hy_goal_write_debugdata()`` takes a directory parameter
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``hy_goal_write_debugdata()`` has a new `const char *dir` argument to communicate the target directory for the debugging data. The old call::
+
+ hy_goal_write_debugdata(goal);
+
+should be changed to achieve the same behavior to::
+
+ hy_goal_write_debugdata(goal, "./debugdata");
+
+Python bindings
+---------------
+
+``Goal.write_debugdata()`` takes a directory parameter
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Analogous to :ref:`core changes <0_4_15_core-label>`.
+
+Package: string attributes are represented by Unicode object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Attributes ``baseurl``, ``location``, ``sourcerpm``, ``version``, ``release``, ``name``, ``arch``, ``description``, ``evr``, ``license``, ``packager``, ``reponame``, ``summary`` and ``url`` of Package object return Unicode string.
+
+
+Changes in 0.4.18
+=================
+
+Core
+----
+
+Deprecated ``hy_advisory_get_filenames``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The function was deprecated because we need more information about packages
+listed in an advisory than just file names. Please use the new function
+``hy_advisory_get_packages()`` in combination with
+``hy_advisorypkg_get_string()`` to obtain the data originally provided by the
+deprecated function.
+
+The old function will be dropped after 2014-10-15 AND no sooner than in 0.4.21.
+
+Python bindings
+---------------
+
+``Repo()`` does not accept ``cost`` keyword argument
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Instead of::
+
+ r = hawkey.Repo('name', cost=30)
+
+use::
+
+ r = hawkey.Repo('name')
+ r.cost = 30
+
+Also previously when no ``cost`` was given it defaulted to 1000. Now the default is 0. Both these aspects were present by mistake and the new interface is consistent with the C library.
+
+Deprecated ``_hawkey.Advisory.filenames``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The attribute was deprecated because the underlying C function was also
+deprecated. Please use the new attribute ``packages`` and the attribute
+``filename`` of the returned objects to obtain the data originally provided by
+the deprecated attribute.
+
+The old attribute will be dropped after 2014-10-15 AND no sooner than in 0.4.21.
+
+
+Changes in 0.4.19
+=================
+
+Python bindings
+---------------
+
+Advisory attributes in Unicode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+All string attributes of ``Advisory`` and ``AdvisoryRef`` objects (except the
+deprecated ``filenames`` attribute) are Unicode objects now.
+
+
+Changes in 0.5.2
+=================
+
+Core
+----
+
+``hy_chksum_str`` returns NULL
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Previously, the function ``hy_chksum_str`` would cause a segmentation fault when it was used
+with incorrect type value. Now it correctly returns NULL if type parameter does not correspond
+to any of expected values.
+
+
+Changes in 0.5.3
+================
+
+Core
+----
+
+New parameter ``logfile`` to ``hy_sack_create()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``hy_sack_create()`` now accepts fifth argument, ``logfile`` to customize log file path.
+If NULL parameter as ``logfile`` is given, then all debug records are written to ``hawkey.log``
+in ``cachedir``. To make your code compile in 0.5.3 without changing functionality, change::
+
+ HySack sack = hy_sack_create(cachedir, arch, rootdir, 0);
+
+to::
+
+ HySack sack = hy_sack_create(cachedir, arch, rootdir, NULL, 0);
+
+Deprecated ``hy_create_cmdline_repo()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The function will be removed since `hy_add_cmdline_package` creates cmdline repository automatically.
+
+The function will be dropped after 2015-06-23 AND no sooner than in 0.5.8.
+
+Python bindings
+---------------
+
+New optional parameter ``logfile`` to ``Sack`` constructor
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This addition lets user specify log file path from :meth:`.Sack.__init__`
+
+``cache_path`` property of ``Sack`` renamed to ``cache_dir``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This change was already announced but it actually never happened.
+
+Deprecated ``Sack`` method ``create_cmdline_repo()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The method will be removed since :meth:`.Sack.add_cmdline_package` creates cmdline repository automatically.
+
+The method will be dropped after 2015-06-23 AND no sooner than in 0.5.8.
+
+
+Changes in 0.5.4
+================
+
+Python bindings
+---------------
+
+Goal: ``install()`` takes a new optional parameter
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the ``optional`` parameter is set to ``True``, hawkey silently skips packages that can not
+be installed.
+
+
+Changes in 0.5.5
+================
+
+Core
+----
+
+Renamed ``hy_sack_load_yum_repo`` to ``hy_sack_load_repo``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Hawkey is package manager agnostic and the ``yum`` phrase could be misleading.
+
+The function will be dropped after 2015-10-27 AND no sooner than in 0.5.8.
+
+Python bindings
+---------------
+
+Sack method `load_yum_repo` has been renamed to :meth:`.Sack.load_repo`
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Hawkey is package manager agnostic and the ``yum`` phrase could be misleading.
+
+The method will be dropped after 2015-10-27 AND no sooner than in 0.5.8.
+
+
+Changes in 0.5.7
+================
+
+Python bindings
+---------------
+
+Package: file attribute is represented by list of Unicode objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sack: `list_arches` method returns list of Unicode objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+Changes in 0.5.9
+================
+
+Core
+----
+
+Deprecated ``hy_goal_req_has_distupgrade()``, ``hy_goal_req_has_erase()`` and ``hy_goal_req_has_upgrade()`` functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To make your code compile in 0.5.9 without changing functionality, change::
+
+ hy_goal_req_has_distupgrade_all(goal)
+ hy_goal_req_has_erase(goal)
+ hy_goal_req_has_upgrade_all(goal)
+
+to::
+
+ hy_goal_has_actions(goal, HY_DISTUPGRADE_ALL)
+ hy_goal_has_actions(goal, HY_ERASE)
+ hy_goal_has_actions(goal, HY_UPGRADE_ALL)
+
+respectively
+
+
+Python bindings
+---------------
+
+Deprecated Goal methods :meth:`Goal.req_has_distupgrade_all`, :meth:`Goal.req_has_erase` and :meth:`Goal.req_has_upgrade_all`
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To make your code compatible with hawkey 0.5.9 without changing functionality,
+change::
+
+ goal.req_has_distupgrade_all()
+ goal.req_has_erase()
+ goal.req_has_upgrade_all()
+
+to::
+
+ goal.actions & hawkey.DISTUPGRADE_ALL
+ goal.actions & hawkey.ERASE
+ goal.actions & hawkey.UPGRADE_ALL
+
+respectively
+
+
+Changes in 0.6.2
+================
+
+Core
+----
+
+The ``hy_advisory_get_filenames()`` API call, the corresponding Python
+property ``filenames`` of class :class:`Advisory` are removed.
+Instead, iterate over ``hy_advisory_get_packages()`` with
+``hy_advisorypkg_get_string()`` and ``HY_ADVISORYPKG_FILENAME``. No
+known hawkey API consumers were using this call.
+
+Hawkey now has a dependency on GLib. Aside from the above
+``hy_advisory_get_filenames()`` call, the Python API is fully
+preserved. The C API has minor changes, but the goal is to avoid
+causing a significant amount of porting work for existing consumers.
+
+The ``hy_package_get_files`` API call now returns a ``char **``,
+allocated via `g_malloc`. Free with `g_strfreev`.
+
+The ``HyStringArray`` type is removed, as nothing now uses it.
+
+:class:`HyPackageList` is now just a :class:`GPtrArray`, though
+the existing API is converted into wrappers. Notably, this means
+you can now use ``g_ptr_array_unref()``.
+
+
+Python bindings
+---------------
+
+Aside from the one change below, the Python bindings should be
+unaffected by the C API changes.
+
+Advisory: The ``filename`` property is removed along with the C API
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Hawkey documentation build configuration file, created by
+# sphinx-quickstart on Tue Aug 7 11:06:24 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+import os
+import re
+
+_dirname = os.path.dirname(__file__)
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Hawkey'
+copyright = u'2012-2015, Red Hat, Licensed under GPLv2+'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+
+def version_readout():
+ fn = os.path.join(_dirname, '../../VERSION.cmake')
+ with open(fn) as f:
+ lines = f.readlines()
+
+ pat = re.compile(r"\d+")
+ major = pat.findall(lines[0])[0]
+ minor = pat.findall(lines[1])[0]
+ micro = pat.findall(lines[2])[0]
+
+ return "{}.{}.{}".format(major, minor, micro)
+
+version = version_readout()
+# The full version, including alpha/beta/rc tags.
+release = '%s-1' % version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Hawkeydoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Hawkey.tex', u'Hawkey Documentation',
+ u'Aleš Kozumplík', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'hawkey', u'Hawkey Documentation',
+ [u'Aleš Kozumplík'], 3)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'Hawkey', u'Hawkey Documentation',
+ u'Aleš Kozumplík', 'Hawkey', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+rst_prolog = """
+.. default-domain:: py
+.. _libsolv: https://github.com/openSUSE/libsolv
+.. _bugzilla: https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=hawkey
+
+"""
--- /dev/null
+..
+ Copyright (C) 2014 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+****
+FAQ
+****
+
+.. contents::
+
+Getting Started
+===============
+
+How do I build it?
+------------------
+
+See the `README <https://github.com/akozumpl/hawkey/tree/master/README.rst>`_.
+
+Are there examples using hawkey?
+--------------------------------
+
+Yes, look at:
+
+* `unit tests <https://github.com/akozumpl/hawkey/tree/master/tests>`_
+* `The Hawkey Testing Hack <https://github.com/akozumpl/hawkey/blob/master/src/hth.c>`_
+* a more complex example is `DNF <https://github.com/akozumpl/dnf/>`_, the Yum fork using hawkey for backend.
+
+Using Hawkey
+============
+
+How do I obtain the repo metadata files to feed to Hawkey?
+----------------------------------------------------------
+
+It is entirely up to you. Hawkey does not provide any means to do this
+automatically, for instance from your `/etc/yum.repos.d` configuration. Use or
+build tools to do that. For instance, both Yum and DNF deals with the same
+problem and inside they employ `urlgrabber <http://urlgrabber.baseurl.org/>`_ to
+fetch the files. A general solution if you work in C is for instance `libcurl
+<http://libcurl.org/>`_. If you are building a nice downloading library that
+integrates well with hawkey, let us know.
+
+Why is a tool to do the downloads not integrated into Hawkey?
+-------------------------------------------------------------
+
+Because downloading things from remote servers is a differnt domain full of its
+own complexities like HTTPS, parallel downloads, error handling and error
+recovery to name a few. Downloading is a concern that can be naturally separated
+from other parts of package metadata managing.
--- /dev/null
+..
+ Copyright (C) 2014 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+####################################
+ Hawkey, the libsolv API Simplified
+####################################
+
+Contents:
+
+.. toctree::
+ :maxdepth: 1
+
+ changes
+ faq
+ tutorial-py
+ reference-py
+ rationale
+
+Indices and tables
+
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
--- /dev/null
+..
+ Copyright (C) 2014 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+****************
+Design Rationale
+****************
+
+.. highlight:: c
+.. _rationale_selectors:
+
+Selectors are not Queries
+=========================
+
+Since both a Query and a Selector work to limit the set of all Sack's packages
+to a subset, it can be suggested the two concepts should be the same and
+e.g. Queries should be used for Goal specifications instead of Selectors::
+
+ // create sack, goal, ...
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "anaconda")
+ hy_goal_install_query(q)
+
+This arrangment was in fact used in hawkey prior to version 0.3.0, just because
+Queries looked like a convenient structure to hold this kind of information. It
+was unfortunately confusing for the programmers: notice how evaluating the Query
+``q`` would generally produce several packages (``anaconda`` for different
+architectures and then different versions) but somehow when the same Query is
+passed into the goal methods it always results in up to one pacakge selected for
+the operation. This is a principal discrepancy. Further, Query is universal and
+allows one to limit the package set with all sorts of criteria, matched in
+different ways (substrings, globbing, set operation) while Selectors only
+support few. Finally, while a fresh Query with no filters applied corresponds to
+all packages of the Sack, a fresh Selector with no limits set is of no meaning.
+
+An alternative to introducing a completely different concept was adding a
+separate constructor function for Query, one that would from the start designate
+the Query to only accept settings compatible with its purpose of becoming the
+selecting element in a Goal operation (in Python this would probably be
+implemented as a subclass of Query). But that would break client's assumptions
+about Query (`the unofficial C++ FAQ
+<http://www.parashift.com/c++-faq/circle-ellipse.html>`_ takes up the topic).
+
+*Implementation note*: Selectors reflect the kind of specifications that can be
+directly translated into Libsolv jobs, without actually searching for a concrete
+package to put there. In other words, Selectors are specifically designed not to
+iterate over the package data (with exceptions, like glob matching) like Queries
+do. While Hawkey mostly aims to hide any twists and complexities of the
+underlying library, in this case the combined reasons warrant a concession.
--- /dev/null
+..
+ Copyright (C) 2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+**********************
+Module level constants
+**********************
+
+.. data:: hawkey.CMDLINE_REPO_NAME
+
+ The string name of the command line repository.
+
+.. data:: hawkey.SYSTEM_REPO_NAME
+
+ The string name of the system repository.
--- /dev/null
+..
+ Copyright (C) 2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+**************
+Error handling
+**************
+
+When an error or an unexpected event occurs during a Hawkey routine, an
+exception is raised:
+
+* if it is a general error that could be common to other Python programs, one of
+ the standard Python built-in exceptions is raised. For instance, ``IOError``
+ and ``TypeError`` can be raised from Hawkey.
+
+* programming errors within Hawkey that cause unexpected or invalid states raise
+ the standard ``AssertionError``. These should be reported as bugs against
+ Hawkey.
+
+* programming errors due to incorrect use of the library usually produce
+ ``hawkey.ValueException`` or one of its subclasses, ``QueryException`` (poorly
+ formed Query) or ``ArchException`` (unrecognized architecture).
+
+* sometimes there is a close call between blaming the error on an input
+ parameter or on something else, beyond the programmer's
+ control. ``hawkey.RuntimeException`` is generally used in this case.
+
+* ``hawkey.ValidationException`` is raised when a function call performs a
+ preliminary check before proceeding with the main operation and this check
+ fails.
+
+The class hierarchy for Hawkey exceptions is::
+
+ +-- hawkey.Exception
+ +-- hawkey.ValueException
+ | +-- hawkey.QueryException
+ | +-- hawkey.ArchException
+ +-- hawkey.RuntimeException
+ +-- hawkey.ValidationException
--- /dev/null
+..
+ Copyright (C) 2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+************
+Repositories
+************
+
+.. class:: hawkey.Repo
+
+ Instances of :class:`hawkey.Repo` point to metadata of packages that are
+ available to be installed. The metadata are expected to be in the "rpm-md"
+ format. `librepo <https://github.com/Tojaj/librepo>`_ may help you with
+ downloading the required files.
+
+ .. attribute:: cost
+
+ An integer specifying a relative cost of accessing this repository. This
+ value is compared when the priorities of two repositories are the same. The
+ repository with *the lowest cost* is picked. It is useful to make the
+ library prefer on-disk repositories to remote ones.
+
+ .. attribute:: filelists_fn
+
+ A valid string path to the readable "filelists" XML file if set.
+
+ .. attribute:: name
+
+ A string name of the repository.
+
+ .. attribute:: presto_fn
+
+ A valid string path to the readable "prestodelta.xml" (also called
+ "deltainfo.xml") file if set.
+
+ .. attribute:: primary_fn
+
+ A valid string path to the readable "primary" XML file if set.
+
+ .. attribute:: priority
+
+ An integer priority value of this repository. If there is more than one
+ candidate package for a particular operation, the one from the repository
+ with *the lowest priority* value is picked, possibly despite being less
+ convenient otherwise (e.g. by being a lower version).
+
+ .. attribute:: repomd_fn
+
+ A valid string path to the readable "repomd.xml" file if set.
+
+ .. attribute:: updateinfo_fn
+
+ A valid string path to the readable "updateinfo.xml" file if set.
+
+ .. method:: __init__(name)
+
+ Initialize the repository with empty :attr:`repomd_fn`, :attr:`primary_fn`,
+ :attr:`filelists_fn` and :attr:`presto_fn`. The priority and the cost are
+ set to ``0``.
+
+ `name` is a string giving the name of the repository. The name should not
+ be equal to :const:`hawkey.SYSTEM_REPO_NAME` nor
+ :const:`hawkey.CMDLINE_REPO_NAME`
--- /dev/null
+..
+ Copyright (C) 2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+*******************************************
+Sack---The fundamental hawkey structure
+*******************************************
+
+.. class:: hawkey.Sack
+
+ Instances of :class:`hawkey.Sack` represent collections of packages. An
+ application typically needs at least one instance because it provides much of
+ the hawkey's functionality.
+
+ .. warning:: Any package instance is not supposed to work interchangeably between
+ :class:`hawkey.Query`, :class:`hawkey.Selector` or :class:`hawkey.Goal`
+ created from different :class:`hawkey.Sack`. Usually for common tasks
+ there is no need to initialize two or more `Sacks` in your program.
+ Sacks cannot be deeply copied.
+
+ .. attribute:: cache_dir
+
+ A read-only string property giving the path to the location where a
+ metadata cache is stored.
+
+ .. attribute:: installonly
+
+ A write-only sequence of strings property setting the provide names of
+ packages that should only ever be installed, never upgraded.
+
+ .. attribute:: installonly_limit
+
+ A write-only integer property setting how many installonly packages with
+ the same name are allowed to be installed concurrently. If ``0``, any
+ number of packages can be installed.
+
+ .. method:: __init__(\
+ cachedir=_CACHEDIR, arch=_ARCH, rootdir=_ROOTDIR, pkgcls=hawkey.Package, \
+ pkginitval=None, make_cache_dir=False, logfile=_LOGFILE)
+
+ Initialize the sack with a default cache directory, log file location set
+ to ``hawkey.log`` in the cache directory, an automatically detected
+ architecture and the current root (``/``) as an installroot. The cache is
+ disabled by default.
+
+ `cachedir` is a string giving a path of a cache location.
+
+ `arch` is a string specifying an architecture.
+
+ `rootdir` is a string giving a path to an installroot.
+
+ `pkgcls` is a class of packages retrieved from the sack. The class'
+ ``__init__`` method must accept two arguments. The first argument is a tuple
+ of the sack and the ID of the package. The second argument is the
+ `pkginitval` argument. `pkginitval` cannot be ``None`` if `pkgcls` is
+ specified.
+
+ `make_cache_dir` is a boolean that specifies whether the cache should be
+ used to speedup loading of repositories or not (see
+ :ref:`\building_and_reusing_the_repo_cache-label`).
+
+ `logfile` is a string giving a path of a log file location.
+
+ .. method:: __len__()
+
+ Returns the number of the packages loaded into the sack.
+
+ .. method:: add_cmdline_package(filename)
+
+ Add a package to a command line repository and return it. The package is specified as a string `filename` of an RPM file. The command line repository will be automatically created if doesn't exist already. It could be referenced later by :const:`hawkey.CMDLINE_REPO_NAME` name.
+
+ .. method:: add_excludes(packages)
+
+ Add a sequence of packages that cannot be fetched by Queries nor Selectors.
+
+ .. method:: add_includes(packages)
+
+ Add a sequence of the only packages that can be fetched by Queries or
+ Selectors.
+
+ This is the inverse operation of :meth:`add_excludes`. Any package that
+ is not in the union of all the included packages is excluded. This works in
+ conjunction with exclude and doesn't override it. So, if you both include
+ and exclude the same package, the package is considered excluded no matter
+ of the order.
+
+ .. method:: disable_repo(name)
+
+ Disable the repository identified by a string *name*. Packages in that
+ repository cannot be fetched by Queries nor Selectors.
+
+ .. method:: enable_repo(name)
+
+ Enable the repository identified by a string *name*. Packages in that
+ repository can be fetched by Queries or Selectors.
+
+ .. warning:: Execution of :meth:`add_excludes`, :meth:`add_includes`,
+ :meth:`disable_repo` or :meth:`enable_repo` methods could cause
+ inconsistent results in previously evaluated :class:`.Query`,
+ :class:`.Selector` or :class:`.Goal`. The rule of thumb is
+ to exclude/include packages, enable/disable repositories at first and
+ then do actual computing using :class:`.Query`, :class:`.Selector`
+ or :class:`.Goal`. For more details see
+ `developer discussion <https://github.com/rpm-software-management/hawkey/pull/87>`_.
+
+ .. method:: evr_cmp(evr1, evr2)
+
+ Compare two EVR strings and return a negative integer if *evr1* < *evr2*,
+ zero if *evr1* == *evr2* or a positive integer if *evr1* > *evr2*.
+
+ .. method:: get_running_kernel()
+
+ Detect and return the package of the currently running kernel. If the
+ package cannot be found, ``None`` is returned.
+
+ .. method:: list_arches()
+
+ List strings giving all the supported architectures.
+
+ .. method:: load_system_repo(repo=None, build_cache=False)
+
+ Load the information about the packages in the system repository (in Fedora
+ it is the RPM database) into the sack. This makes the dependency solving
+ aware of the already installed packages. The system repository is always
+ set to :const:`hawkey.SYSTEM_REPO_NAME`. The information is not written to
+ the cache by default.
+
+ `repo` is an optional :class:`.Repo` object that represents the system
+ repository. The object is updated during the loading.
+
+ `build_cache` is a boolean that specifies whether the information should be
+ written to the cache (see :ref:`\building_and_reusing_the_repo_cache-label`).
+
+ .. method:: load_repo(\
+ repo, build_cache=False, load_filelists=False, load_presto=False, \
+ load_updateinfo=False)
+
+ Load the information about the packages in a :class:`.Repo` into the sack.
+ This makes the dependency solving aware of these packages. The information
+ is not written to the cache by default.
+
+ `repo` is the :class:`.Repo` object to be processed. At least its
+ :attr:`.Repo.repomd_fn` must be set. If the cache has to be updated,
+ :attr:`.Repo.primary_fn` is needed too. Some information about the loading
+ process and some results of it are written into the internal state of the
+ repository object.
+
+ `build_cache` is a boolean that specifies whether the information should be
+ written to the cache (see :ref:`\building_and_reusing_the_repo_cache-label`).
+
+ `load_filelists`, `load_presto` and `load_updateinfo` are booleans that
+ specify whether the :attr:`.Repo.filelists_fn`, :attr:`.Repo.presto_fn` and
+ :attr:`.Repo.updateinfo_fn` files of the repository should be processed.
+ These files may contain information needed for dependency solving,
+ downloading or querying of some packages. Enable it if you are not sure (see
+ :ref:`\case_for_loading_the_filelists-label`).
--- /dev/null
+..
+ Copyright (C) 2014-2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+******************************
+python-hawkey Reference Manual
+******************************
+
+.. contents::
+
+
+Introduction
+============
+
+This reference manual describes Python API to the library. For a quick start
+take a look at :doc:`tutorial-py`. To be sure that you are familiar with our
+deprecation policy, see :doc:`changes`.
+
+.. NOTE::
+
+ The API consists of exactly those elements described in this document, items
+ not documented here can change from release to release. Opening a `bugzilla`_
+ if certain needed functionality is not exposed is the right thing to do.
+
+.. WARNING::
+
+ The manual is not complete yet - the features are being added incrementally
+ these days.
+
+
+Contents
+========
+
+API Documentation Contents
+
+.. toctree::
+ :maxdepth: 2
+
+ reference-py-sack
+ reference-py-errors
+ reference-py-constants
+ reference-py-repo
+
+Indices:
+
+* :ref:`genindex`
--- /dev/null
+..
+ Copyright (C) 2014-2015 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+************************
+ python-hawkey Tutorial
+************************
+
+.. contents::
+
+.. IMPORTANT::
+
+ Please consult every usage of the library with :doc:`reference-py` to be sure
+ what are you doing. The examples mentioned here are supposed to be as simple
+ as possible and may ignore some minor corner cases.
+
+Setup
+=====
+
+First of, make sure hawkey is installed on your system, this should work from your terminal::
+
+ >>> import hawkey
+
+The Sack Object
+===============
+
+*Sack* is an abstraction for a collection of packages. Sacks in hawkey are
+toplevel objects carrying much of hawkey's of functionality. You'll want to
+create one::
+
+ >>> sack = hawkey.Sack()
+ >>> len(sack)
+ 0
+
+Initially, the sack contains no packages.
+
+Loading RPMDB
+=============
+
+hawkey is a lib for listing, querying and resolving dependencies of *packages*
+from *repositories*. On most linux distributions you always have at least *the
+system repo* (in Fedora it is the RPM database). To load it::
+
+ >>> sack.load_system_repo()
+ >>> len(sack)
+ 1683
+
+Hawkey always knows the name of every repository. The system repository is always
+set to :const:`hawkey.SYSTEM_REPO_NAME`. and the client is responsible for naming
+the available repository metadata.
+
+Loading Repositories
+====================
+
+Let's be honest here: all the fun in packaging comes from packages you haven't
+installed yet. Information about them, their *metadata*, can be obtained from
+different sources and typically they are downloaded from an HTTP mirror (another
+possibilities are FTP server, NFS mount, DVD distribution media, etc.). Hawkey
+does not provide any means to discover and obtain the metadata locally: it is up
+to the client to provide valid readable paths to the repository metadata XML
+files. Structures used for passing the information to hawkey are the hawkey
+:class:`Repos <hawkey.Repo>`. Suppose we somehow obtained the metadata and placed it in
+``/home/akozumpl/tmp/repodata``. We can then load the metadata into hawkey::
+
+ >>> path = "/home/akozumpl/tmp/repodata/%s"
+ >>> repo = hawkey.Repo("experimental")
+ >>> repo.repomd_fn = path % "repomd.xml"
+ >>> repo.primary_fn = path % "f7753a2636cc89d70e8aaa1f3c08413ab78462ca9f48fd55daf6dedf9ab0d5db-primary.xml.gz"
+ >>> repo.filelists_fn = path % "0261e25e8411f4f5e930a70fa249b8afd5e86bb9087d7739b55be64b76d8a7f6-filelists.xml.gz"
+ >>> sack.load_repo(repo, load_filelists=True)
+ >>> len(sack)
+ 1685
+
+The number of packages in the Sack will increase by the number of packages found
+in the repository (two in this case, it is an experimental repo after all).
+
+.. _case_for_loading_the_filelists-label:
+
+Case for Loading the Filelists
+==============================
+
+What the ``load_filelists=True`` argument to :meth:`~hawkey.Sack.load_repo` above does is
+instruct hawkey to process the ``<hash>filelists.xml.gz`` file we passed in and
+which contains structured list of absolute paths to all files of all packages
+within the repo. This information can be used for two purposes:
+
+* Finding a package providing given file. For instance, you need the file
+ ``/usr/share/man/man3/fprintf.3.gz`` which is not installed. Consulting
+ filelists (directly or through hawkey) can reveal the file is in the
+ ``man-pages`` package.
+
+* Depsolving. Some packages require concrete files as their dependencies. To
+ know if these are resolvable and how, the solver needs to know what package
+ provides what files.
+
+Some files provided by a package (e.g those in ``/usr/bin``) are always visible
+even without loading the filelists. Well-behaved packages requiring only those
+can be thus resolved directly. Unortunately, there are packages that don't
+behave and it is hard to tell in advance when you'll deal with one.
+
+The strategy for using ``load_filelists=True`` is thus:
+
+* Use it if you know you'll do resolving (i.e. you'll use :class:`Goal`).
+
+* Use it if you know you'll be trying to match files to their packages.
+
+* Use it if you are not sure.
+
+.. _building_and_reusing_the_repo_cache-label:
+
+Building and Reusing the Repo Cache
+===================================
+
+Internally to hold the package information and perform canonical resolving
+hawkey uses `Libsolv`_. One great benefit this library offers is providing
+writing and reading of metadata cache files in libsolv's own binary format
+(files with ``.solv`` extension, typically). At a cost of few hundreds of
+milliseconds, using the solv files reduces repo load times from seconds to tens
+of milliseconds. It is thus a good idea to write and use the solv files every
+time you plan to use the same repo for more than one Sack (which is at least
+every time your hawkey program is run). To do that use ``build_cache=True`` with
+:meth:`~.Sack.load_repo` and :meth:`~.Sack.load_system_repo`::
+
+ >>> sack = hawkey.Sack(make_cache_dir=True)
+ >>> sack.load_system_repo(build_cache=True)
+
+By default, Hawkey creates ``@System.cache`` under the
+``/var/tmp/hawkey-<your_login>-<random_hash>`` directory. This is the hawkey
+cache directory, which you can always delete later (deleting the cache files in
+the process). The ``.solv`` files are picked up automatically the next time you
+try to create a hawkey sack. Except for a much higher speed of the operation
+this will be completely transparent to you:
+
+ >>> s2 = hawkey.Sack()
+ >>> s2.load_system_repo()
+
+By the way, the cache directory (if not set otherwise) also contains a logfile
+with some boring debugging information.
+
+Queries
+=======
+
+Query is the means in hawkey of finding a package based on one or more criteria
+(name, version, repository of origin). Its interface is loosely based on
+`Django's QuerySets
+<https://docs.djangoproject.com/en/1.4/topics/db/queries/>`_, the main concepts being:
+
+* a fresh Query object matches all packages in the Sack and the selection is
+ gradually narrowed down by calls to :meth:`Query.filter`
+
+* applying a :meth:`Query.filter` does not start to evaluate the Query, i.e. the
+ Query is lazy. Query is only evaluated when we explicitly tell it to or when
+ we start to iterate it.
+
+* use Python keyword arguments to :meth:`Query.filter` to specify the filtering
+ criteria.
+
+For instance, let's say I want to find all installed packages which name ends
+with ``gtk``::
+
+ >>> q = hawkey.Query(sack).filter(reponame=hawkey.SYSTEM_REPO_NAME, name__glob='*gtk')
+ >>> for pkg in q:
+ ... print str(pkg)
+ ...
+ NetworkManager-gtk-1:0.9.4.0-9.git20120521.fc17.x86_64
+ authconfig-gtk-6.2.1-1.fc17.x86_64
+ clutter-gtk-1.2.0-1.fc17.x86_64
+ libchamplain-gtk-0.12.2-1.fc17.x86_64
+ libreport-gtk-2.0.10-3.fc17.x86_64
+ pinentry-gtk-0.8.1-6.fc17.x86_64
+ python-slip-gtk-0.2.20-2.fc17.noarch
+ transmission-gtk-2.50-2.fc17.x86_64
+ usermode-gtk-1.109-1.fc17.x86_64
+ webkitgtk-1.8.1-2.fc17.x86_64
+ xdg-user-dirs-gtk-0.9-1.fc17.x86_64
+
+Or I want to find the latest version of all ``python`` packages the Sack knows of::
+
+ >>> q.clear()
+ >>> q = q.filter(name='python', latest_per_arch=True)
+ >>> for pkg in q:
+ ... print str(pkg)
+ ...
+ python-2.7.3-6.fc17.x86_64
+
+You can also test a :class:`Query` for its truth value. It will be true whenever
+the query matched at least one package::
+
+ >>> q = hawkey.Query(sack).filter(file='/boot/vmlinuz-3.3.4-5.fc17.x86_64')
+ >>> if q:
+ ... print 'match'
+ ...
+ match
+ >>> q = hawkey.Query(sack).filter(file='/booty/vmlinuz-3.3.4-5.fc17.x86_64')
+ >>> if q:
+ ... print 'match'
+ ...
+ >>> if not q:
+ ... print 'no match'
+ ...
+ no match
+
+.. NOTE::
+
+ If the Query hasn't been evaluated already then it is evaluated whenever it's
+ length is taken (either via ``len(q)`` or ``q.count()``), when it is tested for
+ truth and when it is explicitly evaluated with ``q.run()``.
+
+Resolving things with Goals
+===========================
+
+Many :class:`~.Sack` sessions culminate in a bout of dependency resolving, that
+is answering a question along the lines of "I have a package X in a repository
+here, what other packages do I need to install/update to have X installed and
+all its dependencies recursively satisfied?" Suppose we want to install `the RTS
+game Spring <http://springrts.com/>`_. First let's locate the latest version of
+the package in repositories::
+
+ >>> q = hawkey.Query(sack).filter(name='spring', latest_per_arch=True)
+ >>> pkg = hawkey.Query(sack).filter(name='spring', latest_per_arch=True)[0]
+ >>> str(pkg)
+ 'spring-88.0-2.fc17.x86_64'
+ >>> pkg.reponame
+ 'fedora'
+
+Then build the :class:`Goal` object and tell it our goal is installing the
+``pkg``. Then we fire off the libsolv's dependency resolver by running the
+goal::
+
+ >>> g = hawkey.Goal(sack)
+ >>> g.install(pkg)
+ >>> g.run()
+ True
+
+``True`` as a return value here indicates that libsolv could find a solution to
+our goal. This is not always the case, there are plenty of situations when there
+is no solution, the most common one being a package should be installed but one
+of its dependencies is missing from the sack.
+
+The three methods :meth:`Goal.list_installs`, :meth:`Goal.list_upgrades` and
+:meth:`Goal.list_erasures` can show which packages should be
+installed/upgraded/erased to satisfy the packaging goal we set out to achieve
+(the mapping of :func:`str` over the results below ensures human readable
+package names instead of numbers are presented)::
+
+ >>> map(str, g.list_installs())
+ ['spring-88.0-2.fc17.x86_64', 'spring-installer-20090316-10.fc17.x86_64', 'springlobby-0.139-3.fc17.x86_64', 'spring-maps-default-0.1-8.fc17.noarch', 'wxBase-2.8.12-4.fc17.x86_64', 'wxGTK-2.8.12-4.fc17.x86_64', 'rb_libtorrent-0.15.9-1.fc17.x86_64', 'GeoIP-1.4.8-2.1.fc17.x86_64']
+ >>> map(str, g.list_upgrades())
+ []
+ >>> map(str, g.list_erasures())
+ []
+
+So what does it tell us? That given the state of the given system and the given
+repository we used, 8 packages need to be installed,
+``spring-88.0-2.fc17.x86_64`` itself included. No packages need to be upgraded
+or erased.
+
+Selector Installs
+-----------------
+
+For certain simple and commonly used queries we can do installs
+directly. Instead of executing a query however we instantiate and pass the
+:meth:`Goal.install` method a :class:`Selector`:
+
+ >>> g = hawkey.Goal(sack)
+ >>> sltr = hawkey.Selector(sack).set(name='emacs-nox')
+ >>> g.install(select=sltr)
+ >>> g.run()
+ True
+ >>> map(str, g.list_installs())
+ ['spring-88.0-2.fc17.x86_64', 'spring-installer-20090316-10.fc17.x86_64', 'springlobby-0.139-3.fc17.x86_64', 'spring-maps-default-0.1-8.fc17.noarch', 'wxBase-2.8.12-4.fc17.x86_64', 'wxGTK-2.8.12-4.fc17.x86_64', 'rb_libtorrent-0.15.9-1.fc17.x86_64', 'GeoIP-1.4.8-2.1.fc17.x86_64']
+ >>> len(g.list_upgrades())
+ 0
+ >>> len(g.list_erasures())
+ 0
+
+Notice we arrived at the same result as before, when a query was constructed and
+iterated first. What :class:`Selector` does when passed to :meth:`Goal.install`
+is tell hawkey to examine its settings and without evaluating it as a
+:class:`Query` it instructs libsolv to find *the best matching package* for it
+and add that for installation. It saves user some decisions like which version
+should be installed or what architecture (this gets very relevant with multiarch
+libraries).
+
+So Selectors usually only install a single package. If you mean to install *all
+packages* matching an arbitrarily complex query, just use the method describe
+above::
+
+ >>> map(goal.install, q)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<diagram program="umlet" version="14.2">
+ <zoom_level>8</zoom_level>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>904</x>
+ <y>480</y>
+ <w>144</w>
+ <h>144</h>
+ </coordinates>
+ <panel_attributes><TRANS_ITEM>
+--
+id
+trans_id
+item_id
+repo_id
+action
+reason
+state
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>808</x>
+ <y>344</y>
+ <w>144</w>
+ <h>56</h>
+ </coordinates>
+ <panel_attributes>REPO
+--
+id
+repoid
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>1120</x>
+ <y>480</y>
+ <w>144</w>
+ <h>144</h>
+ </coordinates>
+ <panel_attributes>TRANS
+--
+id
+dt_begin
+dt_end
+rpmdb_version_begin
+rpmdb_version_end
+releasever
+user_id
+cmdline
+state
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1040</x>
+ <y>512</y>
+ <w>96</w>
+ <h>40</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=1
+
+</panel_attributes>
+ <additional_attributes>10.0;20.0;100.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>696</x>
+ <y>480</y>
+ <w>144</w>
+ <h>80</h>
+ </coordinates>
+ <panel_attributes>ITEM
+--
+id
+item_type
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>832</x>
+ <y>520</y>
+ <w>88</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>m1=1
+m2=0..n</panel_attributes>
+ <additional_attributes>10.0;10.0;90.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>1120</x>
+ <y>688</y>
+ <w>144</w>
+ <h>80</h>
+ </coordinates>
+ <panel_attributes>CONSOLE_OUTPUT
+--
+id
+trans_id
+file_descriptor
+line
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1184</x>
+ <y>616</y>
+ <w>24</w>
+ <h>88</h>
+ </coordinates>
+ <panel_attributes>m1=*
+
+</panel_attributes>
+ <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>984</x>
+ <y>344</y>
+ <w>144</w>
+ <h>56</h>
+ </coordinates>
+ <panel_attributes>ITEM_STATE
+--
+id
+name
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1008</x>
+ <y>392</y>
+ <w>40</w>
+ <h>104</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=1</panel_attributes>
+ <additional_attributes>10.0;110.0;10.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>1120</x>
+ <y>248</y>
+ <w>144</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>TRANS_WITH
+--
+id
+trans_id
+item_id
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>1192</x>
+ <y>312</y>
+ <w>40</w>
+ <h>184</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=1</panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;210.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>760</x>
+ <y>280</y>
+ <w>376</w>
+ <h>216</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=1</panel_attributes>
+ <additional_attributes>450.0;10.0;10.0;10.0;10.0;250.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>688</x>
+ <y>128</y>
+ <w>144</w>
+ <h>48</h>
+ </coordinates>
+ <panel_attributes>config
+--
+key
+value
+
+
+bg=white
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>416</x>
+ <y>464</y>
+ <w>144</w>
+ <h>112</h>
+ </coordinates>
+ <panel_attributes>RPM
+--
+item_id
+name
+epoch
+version
+release
+arch
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>552</x>
+ <y>512</y>
+ <w>88</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>m1=0..1</panel_attributes>
+ <additional_attributes>10.0;10.0;90.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>168</x>
+ <y>656</y>
+ <w>144</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>MODULEMD
+-
+id
+modulemd_stream_id
+version
+context
+arch
+
+
+halign=center
+lt=.
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>928</x>
+ <y>392</y>
+ <w>40</w>
+ <h>104</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=1</panel_attributes>
+ <additional_attributes>10.0;110.0;10.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>392</x>
+ <y>800</y>
+ <w>216</w>
+ <h>88</h>
+ </coordinates>
+ <panel_attributes><MODULEMD_TRANSACTION_ITEM>
+-
+id
+modulemd_stream_id
+modulemd_profile_id (NULL)
+transaction_item_id
+
+
+halign=center
+lt=.</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>496</x>
+ <y>720</y>
+ <w>40</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>m1=0..1
+m2=0..n
+lt=.</panel_attributes>
+ <additional_attributes>10.0;10.0;10.0;100.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>600</x>
+ <y>592</y>
+ <w>320</w>
+ <h>272</h>
+ </coordinates>
+ <panel_attributes>m1=1
+m2=0..n
+lt=.
+</panel_attributes>
+ <additional_attributes>380.0;10.0;140.0;10.0;140.0;310.0;10.0;310.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>432</x>
+ <y>304</y>
+ <w>144</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>COMPS_GROUP
+--
+item_id
+groupid
+name
+translated_name
+// pkg_types: mandatory, default, optional
+pkg_types
+// pkg_types -> rpm_types?
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLSpecialState</id>
+ <coordinates>
+ <x>624</x>
+ <y>504</y>
+ <w>32</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>type=decision</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>648</x>
+ <y>504</y>
+ <w>64</w>
+ <h>40</h>
+ </coordinates>
+ <panel_attributes>m1=1
+</panel_attributes>
+ <additional_attributes>60.0;20.0;10.0;20.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>568</x>
+ <y>344</y>
+ <w>88</w>
+ <h>176</h>
+ </coordinates>
+ <panel_attributes>m1=0..1</panel_attributes>
+ <additional_attributes>10.0;10.0;90.0;10.0;90.0;200.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>544</x>
+ <y>528</y>
+ <w>112</w>
+ <h>184</h>
+ </coordinates>
+ <panel_attributes>m1=0..1
+lt=.</panel_attributes>
+ <additional_attributes>10.0;200.0;120.0;200.0;120.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>432</x>
+ <y>144</y>
+ <w>144</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>COMPS_ENVIRONMENT
+--
+item_id
+environmentid
+name
+translated_name
+pkg_types
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>392</x>
+ <y>656</y>
+ <w>160</w>
+ <h>72</h>
+ </coordinates>
+ <panel_attributes>MODULEMD_PROFILE
+-
+item_id
+modulemd_id
+name
+
+
+halign=center
+lt=.</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>304</x>
+ <y>680</y>
+ <w>104</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>m1=1
+m2=0..n
+lt=.</panel_attributes>
+ <additional_attributes>10.0;10.0;110.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>168</x>
+ <y>808</y>
+ <w>144</w>
+ <h>80</h>
+ </coordinates>
+ <panel_attributes>MODULEMD_STREAM
+-
+id
+name
+stream
+
+
+halign=center
+lt=.</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>232</x>
+ <y>744</y>
+ <w>40</w>
+ <h>80</h>
+ </coordinates>
+ <panel_attributes>lt=.
+m1=1
+m2=0..n
+</panel_attributes>
+ <additional_attributes>10.0;80.0;10.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>304</x>
+ <y>832</y>
+ <w>104</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>lt=.
+m1=0..n
+m2=0..1</panel_attributes>
+ <additional_attributes>10.0;10.0;110.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLPackage</id>
+ <coordinates>
+ <x>160</x>
+ <y>608</y>
+ <w>456</w>
+ <h>304</h>
+ </coordinates>
+ <panel_attributes>Modules
+--
+bg=#FFFFFF
+layer=-1
+lt=.
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLPackage</id>
+ <coordinates>
+ <x>160</x>
+ <y>120</y>
+ <w>456</w>
+ <h>288</h>
+ </coordinates>
+ <panel_attributes>Comps Groups
+--
+bg=#d0d0d0
+layer=-1
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>568</x>
+ <y>184</y>
+ <w>88</w>
+ <h>336</h>
+ </coordinates>
+ <panel_attributes>m1=0..1</panel_attributes>
+ <additional_attributes>10.0;10.0;90.0;10.0;90.0;400.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>176</x>
+ <y>304</y>
+ <w>184</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>COMPS_GROUP_PACKAGE
+--
+id
+group_id
+name
+installed
+pkg_type
+
+bg=yellow
+halign=center
+
+layer=1</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>352</x>
+ <y>344</y>
+ <w>96</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>m1=1
+m2=0..n</panel_attributes>
+ <additional_attributes>10.0;10.0;100.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>176</x>
+ <y>144</y>
+ <w>184</w>
+ <h>96</h>
+ </coordinates>
+ <panel_attributes>COMPS_ENVIRONMENT_GROUP
+--
+id
+environment_id
+groupid
+installed
+group_type
+
+bg=yellow
+halign=center
+
+layer=1</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>352</x>
+ <y>184</y>
+ <w>96</w>
+ <h>32</h>
+ </coordinates>
+ <panel_attributes>m1=1
+m2=0..n</panel_attributes>
+ <additional_attributes>10.0;10.0;100.0;10.0</additional_attributes>
+ </element>
+ <element>
+ <id>UMLPackage</id>
+ <coordinates>
+ <x>160</x>
+ <y>432</y>
+ <w>456</w>
+ <h>160</h>
+ </coordinates>
+ <panel_attributes>RPMs
+--
+bg=#d0d0d0
+layer=-1
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLPackage</id>
+ <coordinates>
+ <x>688</x>
+ <y>216</y>
+ <w>584</w>
+ <h>560</h>
+ </coordinates>
+ <panel_attributes>Transaction
+--
+bg=#d0d0d0
+layer=-1
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>UMLClass</id>
+ <coordinates>
+ <x>904</x>
+ <y>688</y>
+ <w>144</w>
+ <h>80</h>
+ </coordinates>
+ <panel_attributes>ITEM_REPLACED_BY
+--
+trans_item_id
+by_trans_item_id
+
+bg=yellow
+halign=center
+</panel_attributes>
+ <additional_attributes/>
+ </element>
+ <element>
+ <id>Relation</id>
+ <coordinates>
+ <x>968</x>
+ <y>616</y>
+ <w>40</w>
+ <h>88</h>
+ </coordinates>
+ <panel_attributes>m1=0..n
+m2=0..n</panel_attributes>
+ <additional_attributes>10.0;90.0;10.0;10.0</additional_attributes>
+ </element>
+</diagram>
--- /dev/null
+# Unified DNF history database diagram
+- use [Umletino](http://www.umlet.com/umletino/umletino.html) or [Umlet](http://www.umlet.com/) to view, edit or export
+- in case of question please contact Eduard Čuba <ecuba@redhat.com>
--- /dev/null
+configure_file("version.xml.in" ${CMAKE_CURRENT_SOURCE_DIR}/version.xml)
+
+if(WITH_GTKDOC)
+ find_package(GtkDoc REQUIRED)
+
+ if(GTKDOC_FOUND)
+ add_custom_command(OUTPUT doc-scan
+ COMMAND ${GTKDOC_SCAN_EXE}
+ --source-dir=${CMAKE_SOURCE_DIR}/libdnf
+ --module=libdnf
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ add_custom_command(OUTPUT doc-mkdb
+ COMMAND ${GTKDOC_MKDB_EXE}
+ --sgml-mode
+ --output-format=xml
+ --module=libdnf
+ --source-dir=${CMAKE_SOURCE_DIR}/libdnf
+ DEPENDS doc-scan
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ add_custom_command(OUTPUT doc-mkhtml
+ COMMAND ${GTKDOC_MKHTML_EXE}
+ libdnf
+ ${CMAKE_SOURCE_DIR}/docs/libdnf/libdnf-docs.sgml
+ DEPENDS doc-mkdb
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/html"
+ )
+ add_custom_target(doc-gtk DEPENDS doc-scan doc-mkdb doc-mkhtml)
+ else()
+ message(FATAL_ERROR "gtk-doc not found")
+ endif()
+
+ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/html/ DESTINATION share/gtk-doc/html/libdnf)
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py)
+
+add_custom_target(doxygen
+ doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ COMMENT "Building doxygen xml files"
+)
+add_custom_target(sphinx-html
+ sphinx-build -c ${CMAKE_CURRENT_BINARY_DIR} -b html
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/_build
+ COMMENT "Building html documentation"
+)
+add_custom_target(doc)
+add_dependencies(sphinx-html doxygen)
+add_dependencies(doc sphinx-html)
--- /dev/null
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "My Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @CMAKE_SOURCE_DIR@/libdnf/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.pyw \
+ *.f90 \
+ *.f95 \
+ *.f03 \
+ *.f08 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# libdnf documentation build configuration file, created by
+# sphinx-quickstart on Fri Nov 10 18:35:37 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['breathe']
+
+breathe_projects = {'libdnf': '@CMAKE_CURRENT_BINARY_DIR@/xml/'}
+breathe_default_project = 'libdnf'
+
+# Add any paths that contain templates here, relative to this directory.
+# templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libdnf'
+copyright = u'2017, Red Hat'
+author = u'Red Hat'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'1.0'
+# The full version, including alpha/beta/rc tags.
+release = u'1.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# html_static_path = ['_static']
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libdnfdoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'libdnf.tex', u'libdnf Documentation',
+ u'Red Hat', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'libdnf', u'libdnf Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'libdnf', u'libdnf Documentation',
+ author, 'libdnf', 'One line description of project.',
+ 'Miscellaneous'),
+]
--- /dev/null
+/* common.css - MoinMoin Default Styles
+
+ Copyright (c) 2001, 2002, 2003 by Jürgen Hermann
+*/
+
+/* content styles */
+
+html {
+ background-color: white;
+ color: black;
+}
+
+h2 {
+ font-size: 1.6em;
+}
+
+h3 {
+ font-size: 1.3em;
+}
+
+h4, h5, h6 {
+ font-size: 1em;
+}
+
+li p {
+ margin: .2em 0;
+}
+
+li.gap {
+ margin-top: 8pt;
+}
+
+a img {
+ border: 0;
+}
+
+img.drawing {
+ border: 0;
+}
+
+dt {
+ font-weight: bold;
+}
+
+pre {
+ padding: .5em;
+ white-space: pre-wrap;
+}
+
+body {
+ margin-top: 2em;
+ margin-left: 5%;
+ margin-right: 5%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2b5e82;
+}
+
+a:link {
+ background-color: inherit;
+ color: #2b5e82;
+}
+
+a:visited {
+ background-color: inherit;
+ color: #52188b;
+}
+
+pre {
+ border: 1px solid #CBCBCB;
+ background-color: #FFF8ED;
+ color: black;
+}
+
+hr {
+ clear: both;
+ border-style: none;
+ background-color: #CBCBCB;
+ color: #CBCBCB;
+}
+
+p.footer {
+ color: #000000;
+ text-align: center;
+ font-size: 9px;
+}
+
+table {
+ border: 0;
+ width: 100%;
+}
+.center {
+ text-align: center;
+}
+div.nav a {
+ border-right: 1px solid black;
+ padding-right: 4px;
+}
+div.nav :last-child {
+ border-right: none;
+}
--- /dev/null
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+ <meta name="robots" content="index,follow">
+ <link rel="stylesheet" type="text/css" media="all" href="common.css">
+ <title>libdnf</title>
+ </head>
+ <body>
+ <div class="nav center">
+ <a href="index.htm">Homepage</a>
+ <a href="docs/">Documentation</a>
+ <a href="releases/">Releases</a>
+ <a href="https://github.com/rpm-software-management/libhif">Browse source code</a>
+ </div>
+ <h1>libdnf</h1>
+ <p>
+ This library provides a simple package manager interface using hawkey and
+ librepo.
+ </p>
+
+ <h2>Getting Started</h2>
+ <p>
+ To install the libdnf library you either need to install the
+ <code>libdnf</code> package from your distributor, or you can build a local
+ copy. To do the latter just do:
+<pre>
+dnf install automake autoconf libtool glib-devel
+./autogen.sh
+make
+make install
+</pre>
+
+ <h2>Hacking</h2>
+ <p>
+ If you want a new feature, or have found a bug or a way to crash this library,
+ please report as much information as you can to the
+ <a href="https://github.com/rpm-software-management/libhif/issues">issue tracker</a>
+ - patches very welcome.
+ </p>
+ <p>
+ New functionality or crash fixes should include a test in `src/dnf-self-test.c`
+ to ensure we don't regress in the future. New functionality should also be
+ thread safe and also not leak *any* memory for success or failure cases.
+ </p>
+
+ <h2>License</h2>
+ <p>
+ LGPLv2+
+ </p>
+
+ <p class="footer">
+ Copyright <a href="mailto:richard@hughsie.com">Richard Hughes 2014</a><br>
+ <a href="http://validator.w3.org/check/referer">Optimized</a>
+ for <a href="http://www.w3.org/">standards</a>.
+ </p>
+ </body>
+</html>
--- /dev/null
+.. libdnf documentation main file, created by
+ sphinx-quickstart on Fri Nov 10 18:35:37 2017.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+libdnf C++ documentation
+==================================
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+Public API Reference
+=====================
+
+.. doxygenclass:: Swdb
+ :members:
+
+.. doxygenclass:: Transaction
+ :members:
+
+.. doxygenclass:: RPMItem
+ :members:
+
+.. doxygenclass:: Repo
+ :members:
+
+.. doxygenclass:: TransactionItem
+ :members:
+
+.. doxygenclass:: CompsGroupItem
+ :members:
+
+.. doxygenclass:: CompsGroupPackage
+ :members:
+
+.. doxygenclass:: CompsEnvironmentItem
+ :members:
+
+.. doxygenclass:: CompsEnvironmentGroup
+ :members:
+
+.. doxygenenum:: TransactionItemReason
+
+.. doxygenenum:: TransactionItemAction
+
+Internal API Reference
+======================
+
+.. doxygenclass:: Item
+ :members:
+
+.. doxygenclass:: Transformer
+ :members:
+
+.. doxygenclass:: SQLite3
+ :members:
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+ <bookinfo>
+ <title>libdnf Reference Manual</title>
+ <releaseinfo>
+ for libdnf &version;
+ </releaseinfo>
+ <authorgroup>
+ <author>
+ <firstname>Richard</firstname>
+ <surname>Hughes</surname>
+ <affiliation>
+ <address>
+ <email>richard@hughsie.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2014</year>
+ <holder>Richard Hughes</holder>
+ </copyright>
+ </bookinfo>
+
+ <reference id="libdnf">
+ <title>libdnf library</title>
+ <partintro>
+ <para>
+ This part documents libdnf.
+ </para>
+ </partintro>
+ <xi:include href="xml/dnf-context.xml"/>
+ <xi:include href="xml/dnf-lock.xml"/>
+ <xi:include href="xml/dnf-repo-loader.xml"/>
+ <xi:include href="xml/dnf-repo.xml"/>
+ <xi:include href="xml/dnf-state.xml"/>
+ <xi:include href="xml/dnf-transaction.xml"/>
+ </reference>
+
+ <reference id="libdnf-helpers">
+ <title>libdnf helpers</title>
+ <partintro>
+ <para>
+ This part dociments the helper functionality.
+ </para>
+ </partintro>
+ <xi:include href="xml/dnf-goal.xml"/>
+ <xi:include href="xml/dnf-keyring.xml"/>
+ <xi:include href="xml/dnf-sack.xml"/>
+ <xi:include href="xml/dnf-utils.xml"/>
+ <xi:include href="xml/dnf-version.xml"/>
+ <xi:include href="xml/dnf-package.xml"/>
+ <xi:include href="xml/dnf-rpmts.xml"/>
+ <xi:include href="xml/dnf-types.xml"/>
+ </reference>
+
+ <xi:include href="xml/annotation-glossary.xml">
+ <xi:fallback />
+ </xi:include>
+
+</book>
--- /dev/null
+@LIBDNF_VERSION@
--- /dev/null
+..
+ Copyright (C) 2014-2018 Red Hat, Inc.
+
+ This copyrighted material is made available to anyone wishing to use,
+ modify, copy, or redistribute it subject to the terms and conditions of
+ the GNU General Public License v.2, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY expressed or implied, including the implied warranties of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details. You should have received a copy of the
+ GNU General Public License along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
+ source code or documentation are not subject to the GNU General Public
+ License and may only be used or replicated with the express permission of
+ Red Hat, Inc.
+
+######################
+ LIBDNF Release Notes
+######################
+
+====================
+0.73.2 Release Notes
+====================
+
+- Bug fixes:
+ - MergedTransaction: Fix invalid memory access when dropping items
+ - ConfigParser: fix use-out-of-scope leaks
+ - Fix "microdnf cannot reinstall curl-minimal"
+ - Fix up some comments in addCountmeFlag()
+ - Fix countme bucket calculation
+
+- Others:
+ - Add tests for shell-style variable expansion
+
+====================
+0.73.1 Release Notes
+====================
+
+- Bug fixes:
+ - Fix https://issues.redhat.com/browse/RHEL-27657
+ - subject-py: Fix memory leak
+
+- Others:
+ - MergedTransaction: Calculate RPM difference between two same versions as no-op
+ - Onboard packit tests
+ - Add virtual destructor to TransactionItem
+
+====================
+0.73.0 Release Notes
+====================
+
+- Major changes:
+ - filelists metadata not loaded by default
+ - deltarpm disabled by default
+
+- New features:
+ - conf: Introduce new optional_metadata_types option to load filelists on demand
+ - goal: Method for detecting file dependency problems
+
+Bugs fixed in 0.73.0:
+
+* :rhbug:`2252128`
+* :rhbug:`2254789`
+
+====================
+0.72.0 Release Notes
+====================
+
+- New features:
+ - conf: Add limited shell-style variable expansion (RhBug:1789346)
+ - conf: Add support for $releasever_major, $releasever_minor (RhBug:1789346)
+ - repo: Don't download the repository if the local cache is up to date
+
+- Bug fixes:
+ - Avoid reinstalling installonly packages marked for ERASE (RhBug:2163474)
+ - transaction: Save the reason for installing (RhBug:1733274)
+ - hawkey.subject: get_best_selectors only obsoleters of latest (RhBug:2183279,2176263)
+
+- Others:
+ - Allow DNF to be removed by DNF 5 (RhBug:2221907)
+ - Include dist-info for python3-libdnf
+ - bindings: Load all modules with RTLD_GLOBAL
+ - Update translations
+
+Bugs fixed in 0.72.0:
+
+* :rhbug:`2163474`
+* :rhbug:`1733274`
+* :rhbug:`2183279`
+* :rhbug:`2176263`
+* :rhbug:`1789346`
+* :rhbug:`2221907`
+
+====================
+0.71.0 Release Notes
+====================
+
+- New features:
+ - PGP: Use new librepo PGP API, remove gpgme dependency
+ - API: Basic support for OpenPGP public keys
+ - Make code C++20 compatible
+
+- Bug fixes:
+ - Avoid using GNU extensions in the dependency splitter regex
+ - filterAdvisory: match installed_solvables sort with lower_bound (RhBug:2212838)
+
+Bugs fixed in 0.71.0:
+
+* :rhbug:`2212838`
+
+====================
+0.70.2 Release Notes
+====================
+
+- Fix #1558: Don't assume inclusion of cstdint
+- Disconnect monitors in `dnf_repo_loader_finalize()` (RhBug:2070153)
+
+- New features:
+ - Support "proxy=_none_" in main config (RhBug:2155713)
+
+Bugs fixed in 0.70.2:
+
+* :rhbug:`2070153`
+* :rhbug:`2155713`
+
+====================
+0.70.1 Release Notes
+====================
+
+- New features:
+ - Add repoid to solver errors for RPMs (RhBug:2179413)
+
+- Others:
+ - Avoid using obsolete RPM API and drop redundant calls
+ - Remove DNF from list of protected packages
+
+Bugs fixed in 0.70.1:
+
+* :rhbug:`2179413`
+
+====================
+0.70.0 Release Notes
+====================
+
+- Security fixes:
+ - Allow change of architecture for packages during security updates with noarch involved (RhBug:2124483)
+
+- Bug fixes:
+ - "dnf_keyring_add_public_keys": reset localError to NULL after free (RhBug:2121222)
+ - context: Get RPM db path from RPM
+ - Fix memory leak of SolvUserdata
+
+Bugs fixed in 0.70.0:
+
+* :rhbug:`2124483`
+* :rhbug:`2121222`
+
+====================
+0.69.0 Release Notes
+====================
+
+- New features:
+ - Expose librepo max_downloads_per_mirror configuration
+
+====================
+0.68.0 Release Notes
+====================
+
+- New features:
+ - context: Support <package-spec> (NEVRA forms, provides, file provides) including globs in the dnf_context_remove func (RhBug:2084602)
+
+- Bug fixes:
+ - dnf-context: Disconnect signal handler before dropping file monitor ref
+ - Filter out advisory pkgs with different arch during advisory upgrade, fixes possible problems in dependency resulution (RhBug:2088149)
+ - Gracefully handle failure to open repo primary file
+ - Fix listing a repository without cpeid (RhBug:2066334)
+
+Bugs fixed in 0.68.0:
+
+* :rhbug:`2084602`
+* :rhbug:`2088149`
+* :rhbug:`2066334`
+
+====================
+0.67.0 Release Notes
+====================
+
+- New features:
+ - Add 'loongarch' support
+
+- Bug fixes:
+ - Use dnf solv userdata to check versions and checksum (RhBug:2027445)
+ - context: Substitute all repository config options (RhBug:2076853)
+
+Bugs fixed in 0.67.0:
+
+* :rhbug:`2027445`
+* :rhbug:`2076853`
+
+====================
+0.66.0 Release Notes
+====================
+
+- Bug fixes:
+ - Use `rpmdbCookie` from librpm, remove `hawkey.Sack._rpmdb_version`
+ - Fix handling transaction id in resolveTransactionItemReason (RhBug:2010259,2053014)
+ - Remove deprecated assertions (RhBug:2027383)
+ - Skip rich deps for autodetection of unmet dependencies (RhBug:2033130, 2048394)
+ - Increase required rpm version since we use `rpmdbCookie()`
+
+Bugs fixed in 0.66.0:
+
+* :rhbug:`2033130`
+* :rhbug:`2027383`
+* :rhbug:`2010259`
+* :rhbug:`2053014`
+
+====================
+0.65.0 Release Notes
+====================
+
+- New features:
+ - Add support for excluding packages to be installed as weak dependencies
+ - Add support for autodetecting packages to be excluded from being installed as weak dependencies
+
+- Bug fixes:
+ - Turn off strict validation of modulemd documents (RhBug:2004853,2007166,2007167)
+
+Bugs fixed in 0.65.0:
+
+* :rhbug:`2004853`
+* :rhbug:`2007166`
+* :rhbug:`2007167`
+
+====================
+0.64.0 Release Notes
+====================
+
+- Implement logic for demodularization of modular rpms (RhBug:1805260)
+- DnfContext: fix handling of default module profiles
+- ModuleMetadata: gracefully handle modules with no defaults
+- Remove failovermethod config option (RhBug:1961083)
+
+Bugs fixed in 0.64.0:
+
+* :rhbug:`1961083`
+* :rhbug:`1805260`
+
+====================
+0.63.1 Release Notes
+====================
+
+- Add hy_query_get_advisory_pkgs to C API (RhBug:1960561)
+- Add dnf_advisorypkg_get_advisory()
+
+- Bug fixes:
+ - DNF does not fail on non UTF-8 file names in a package (RhBug:1893176)
+ - Improve error-reporting for modular functions
+
+Bugs fixed in 0.63.1:
+
+* :rhbug:`1893176`
+* :rhbug:`1960561`
+
+====================
+0.63.0 Release Notes
+====================
+
+- ModuleProfile: add isDefault()
+- ModulePackage: add getDefaultProfile()
+
+- New features:
+ - Add new dnf_context_module_install() C API
+
+- Bug fixes:
+ - Fix a crash when [media] section in .treeinfo is missing for bootable media (RhBug:1946024)
+
+Bugs fixed in 0.63.0:
+
+* :rhbug:`1946024`
+
+====================
+0.62.0 Release Notes
+====================
+
+- Bump version to fix tag in upstream release
+
+Bugs fixed in 0.62.0:
+
+
+====================
+0.61.1 Release Notes
+====================
+
+- Fix: Fully set ssl in newHandle function
+- [conf] Add options for working with certificates used with proxy
+- lock: Switch return-if-fail to assert to quiet gcc -fanalyzer
+- Modify module NSVCA parsing - context definition (RhBug:1926771)
+- libdnf.h: Remove overall extern "C"
+- [context] Fix: dnf_package_is_installonly (RhBug:1928056)
+- Fix problematic language
+- Add getApplicablePackages to advisory and isApplicable to advisorymodule
+- Keep isAdvisoryApplicable to preserve API
+- Run ModulePackageContainerTest tests in tmpdir, merge interdependent
+- [context] Support config file option "proxy_auth_method", defaults "any"
+
+- Security fixes:
+ - Hardening: add signature check with rpmcliVerifySignatures (RhBug:1932079)
+
+- New features:
+ - do not allow 1 as installonly_limit value (RhBug:1926261)
+ - Add a config option to check TLS certificate revocation status (using OCSP stapling), defaults to false (RhBug:1814383)
+
+- Bug fixes:
+ - Bugs fixed (RhBug:1916786)
+
+Bugs fixed in 0.61.1:
+
+* :rhbug:`1921063`
+* :rhbug:`1814383`
+* :rhbug:`1932079`
+* :rhbug:`1926261`
+* :rhbug:`1847035`
+
+====================
+0.60.0 Release Notes
+====================
+
+- Fix repo.fresh() implementation
+- build-sys: Add ENABLE_STATIC option
+- Fix: Fully set ssl in newHandle function
+- [conf] Add options for working with certificates used with proxy
+- Apply proxy certificate options
+- lock: Switch return-if-fail to assert to quiet gcc -fanalyzer
+- build-sys: Clean up message about Python bindings
+- Modify module NSVCA parsing - context definition (RhBug:1926771)
+- [context] Fix: dnf_package_is_installonly (RhBug:1928056)
+- Fix problematic language
+- Add getApplicablePackages to advisory and isApplicable to advisorymodule
+- Keep isAdvisoryApplicable to preserve API
+- Run ModulePackageContainerTest tests in tmpdir, merge interdependent
+- [context] Support config file option "proxy_auth_method", defaults "any"
+
+- Bug fixes:
+ - Support main config file option "installonlypkgs". Changes behaviour of microdnf and PackageKit.
+ - Support main config file option "protected_packages". Changes behaviour of microdnf and PackageKit.
+ - Properly handle multiple collections in updateinfo.xml (RhBug:1804234)
+
+Bugs fixed in 0.60.0:
+
+* :rhbug:`1928056`
+* :rhbug:`1804234`
+* :rhbug:`1926771`
+
+====================
+0.58.0 Release Notes
+====================
+
+- Option: Add reset() method
+- Add OptionBinds::getOption() method
+- [context] Add dnf_repo_conf_from_gkeyfile() and dnf_repo_conf_reset()
+- [context] Add support for options: minrate, throttle, bandwidth, timeout
+- [context] Remove g_key_file_get_string() from dnf_repo_set_keyfile_data()
+- Allow loading ext metadata even if only cache (solv) is present
+- Add ASAN_OPTIONS for test_libdnf_main
+- [context,API] Functions for accessing main/global configuration options
+- [context,API] Function for adding setopt
+- Add getter for modular obsoletes from ModuleMetadata
+- Add ModulePackage.getStaticContext() and getRequires()
+- Add compatible layer for MdDocuments v2
+- Fix modular queries with the new solver
+- Improve formatting of error string for modules
+- Change mechanism of module conflicts
+- Fix load/update FailSafe
+
+- New features:
+ - Extend repo loadCache method with ignoreMissing parameter to allow loading incomplete xml cache (repomd.xml is required). (RhBug:1865803)
+ - Add a new option module_obsoletes
+ - Add new API applyObsoletes() function to apply modular obsoletes
+ - Extend filter_modules with an optional parameter to enable applying modular obsoletes
+
+Bugs fixed in 0.58.0:
+
+* :rhbug:`1918818`
+* :rhbug:`1865803`
+
+====================
+0.55.2 Release Notes
+====================
+
+- Add a dnf sanitizers wrapper to /etc/profile.d
+- Improve performance of query installed() and available()
+- Swdb: Add a method to get the current transaction
+- [modules] Add special handling for src artifacts (RhBug:1809314)
+- Better msgs if "basecachedir" or "proxy_password" isn't set (RhBug:1888946)
+
+- New features:
+ - Add new options module_stream_switch
+ - Support allow_vendor_change setting in dnf context API
+
+Bugs fixed in 0.55.2:
+
+* :rhbug:`1888946`
+* :rhbug:`1809314`
+
+====================
+0.55.0 Release Notes
+====================
+
+- Add vendor to dnf API (RhBug:1876561)
+- Add formatting function for solver error
+- Add error types in ModulePackageContainer
+- Implement module enable for context part
+- Improve string formatting for translation
+- Remove redundant printf and change logging info to notice (RhBug:1827424)
+- Add allow_vendor_change option (RhBug:1788371) (RhBug:1788371)
+
+
+====================
+0.54.2 Release Notes
+====================
+
+- history: Fix dnf history rollback when a package was removed (RhBug:1683134)
+- Add support for HY_GT, HY_LT in query nevra_strict
+- Fix parsing empty lines in config files
+- Accept '==' as an operator in reldeps (RhBug:1847946)
+- Add log file level main config option (RhBug:1802074)
+- Add protect_running_kernel configuration option (RhBug:1698145)
+- Context part of libdnf cannot assume zchunk is on (RhBug:1851841,1779104)
+- Fix memory leak of resultingModuleIndex and handle g_object refs
+- Redirect librepo logs to libdnf logs with different source
+- Introduce changelog metadata in commit messages
+- Add hy_goal_lock
+- Update Copr targets for packit and use alias
+- Enum/String conversions for Transaction Store/Replay
+- utils: Add a method to decode URLs
+- Unify hawkey.log line format with the rest of the logs
+
+====================
+0.48.0 Release Notes
+====================
+
+- swdb: Catch only SQLite3 exceptions and simplify the messages
+- MergedTransaction list multiple comments (RhBug:1773679)
+- Modify CMake to pull *.po files from weblate
+- Optimize DependencyContainer creation from an existing queue
+- fix a memory leak in dnf_package_get_requires()
+- Fix memory leaks on g_build_filename()
+- Fix memory leak in dnf_context_setup()
+- Add `hy_goal_favor` and `hy_goal_disfavor`
+- Define a cleanup function for `DnfPackageSet`
+- dnf-repo: fix dnf_repo_get_public_keys double-free
+- Do not cache RPMDB
+- Use single-quotes around string literals used in SQL statements
+- SQLite3: Do not close the database if it wasn't opened (RhBug:1761976)
+- Don't create a new history DB connection for in-memory DB
+- transaction/Swdb: Use a single logger variable in constructor
+- utils: Add a safe version of pathExists()
+- swdb: Handle the case when pathExists() fails on e.g. permission
+- Repo: prepend "file://" if a local path is used as baseurl
+- Move urlEncode() to utils
+- utils: Add 'exclude' argument to urlEncode()
+- Encode package URL for downloading through librepo (RhBug:1817130)
+- Replace std::runtime_error with libdnf::RepoError
+- Fixes and error handling improvements of the File class
+- [context] Use ConfigRepo for gpgkey and baseurl (RhBug:1807864)
+- [context] support "priority" option in .repo config file (RhBug:1797265)
+
+====================
+0.47.0 Release Notes
+====================
+
+- Fix release version
+
+====================
+0.46.2 Release Notes
+====================
+
+- Add prereq_ignoreinst & regular_requires properties for pkg (RhBug:1543449)
+- Reset active modules when no module enabled or default (RhBug:1767351)
+- Add comment option to transaction (RhBug:1773679)
+- Failing to get module defauls is a recoverable error
+- Baseurl is not exclusive with mirrorlist/metalink (RhBug: 1775184)
+- Add new function to reset all modules in C API (dnf_context_reset_all_modules)
+- [context] Fix to preserve additionalMetadata content (RhBug:1808677)
+- Fix filtering of DepSolvables with source rpms (RhBug:1812596)
+- Add setter for running kernel protection setting
+- Handle situation when an unprivileged user cannot create history database (RhBug:1634385)
+- Add query filter: latest by priority
+- Add DNF_NO_PROTECTED flag to allow empty list of protected packages
+- Remove 'dim' option from terminal colors to make them more readable (RhBug:1807774,1814563)
+- [context] Error when main config file can't be opened (RhBug:1794864)
+- [context] Add function function dnf_context_is_set_config_file_path
+
+====================
+0.45.0 Release Notes
+====================
+
+- Config options: only first empty value clears existing (RhBug:1788154)
+- Make parsing of reldeps more strict (RhBug:1788107)
+- [context] Support repositories defined in main configuration file
+- Fix filtering packages by advisory when more versions and arches are available (RhBug:1770125)
+- Add expanding solvable provides for dependency matching (RhBug:1534123)
+- DnfRepo: fix module_hotfixes keyfile priority level
+- Add custom exceptions to libdnf interface
+- [conf] Set useful default colors when color is enabled
+- Port to libmodulemd-2 API (RhBug:1693683)
+
+====================
+0.43.1 Release Notes
+====================
+
+- Allow excluding packages with "excludepkgs" and globs
+- Add two new query filters: obsoletes_by_priority, upgrades_by_priority
+- [context] Use installonly_limit from global config (RhBug:1256108)
+- [context] Add API to get/set "install_weak_deps"
+- [context] Add wildcard support for repo_id in dnf_context_repo_enable/disable (RhBug:1781420)
+- [context] Adds support for includepkgs in repository configuration.
+- [context] Adds support for excludepkgs, exclude, includepkgs, and disable_excludes in main configuration.
+- [context] Added function dnf_transaction_set_dont_solve_goal
+- [context] Added functions dnf_context_get/set_config_file_path
+- [context] Respect "plugins" global conf value
+- [context] Add API to disable/enable plugins
+
+====================
+0.39.1 Release Notes
+====================
+
+- Report reason how package was excluded (RhBug:1649754)
+- Additional Arm detection improvements (RhBug:1691430)
+- Set skip_if_unavailable for media repos to skip their update (RhBug:1716067)
+- Add support of xml:base for remote and local url in context (RhBug:1734350, 1717865)
+
+====================
+0.38.1 Release Notes
+====================
+
+- Handle NoModuleException in dnf_context_reset_modules (RhBug:1767453)
+- Add missing C function hy_nevra_free() for HyNevra deallocation
+- Context part of libdnf now uses metadata_expire from global configuration
+
+====================
+0.37.1 Release Notes
+====================
+
+- Change the best option default to false
+- Use more descriptive message when failed to retrieve GPG key (RhBug:1605117)
+- Add removeMetadataTypeFromDownload function to the API
+- Context part of libdnf can now read vars (urlvars) from dirs and environment
+- Throw exception immediately if file cannot be opened
+- Add test when there is no primary metadata in compatible format (RhBug:1744960)
+- Various improvements to countme features
+- Don't abort on rpmdb checksum calculation failure
+- Enable module dependency trees when using set_modules_enabled_by_pkgset() (RhBug:1762314)
+- Resolve problem with --best and search in provides (RhBug:1737469)
+- New method "Query::filterSubject()", replaces Solution::getBestSolution()
+- The Solution class was removed
+- Add query argument into get_best_query and get_best_solution
+- Add module reset function into dnf_context
+- Add method to get all repository metadata locations
+- Catch NoModuleException in case of not existent value was used in persistor (RhBug:1761773)
+
+====================
+0.35.5 Release Notes
+====================
+
+- Fix crash in PackageKit (RhBug:1636803)
+- Do not create @System.solv files (RhBug:1707995)
+- Set LRO_CACHEDIR so zchunk works again (RhBug:1739867)
+- Don't reinstall modified packages with the same NEVRA (RhBug:1644241)
+- Fix bug when moving temporary repository metadata after download (RhBug:1700341)
+- Improve detection of extras packages by comparing (name, arch) pair instead of full NEVRA (RhBuh:1684517)
+- Improve handling multilib packages in the history command (RhBug:1728637)
+- Repo download: use full error description into the exception text (RhBug:1741442)
+- Properly close hawkey.log (RhBug:1594016)
+- Fix dnf updateinfo --update to not list advisories for packages updatable only from non-enabled modules
+- Apply modular filtering by package name (RhBug:1702729)
+
+====================
+0.35.3 Release Notes
+====================
+
+- Detect armv7 with crypto extension only on arm version >= 8
+- A new standardized User-Agent field consisting of the libdnf and OS version
+ (including the variant) (RhBug:1156007)
+- Add basic countme support (RhBug:1647454)
+
+====================
+0.35.2 Release Notes
+====================
+
+- Make libdnf own its plugin directory (RhBug:1714265)
+- Don't disable nonexistent but required repositories (RhBug:1689331)
+- Set priority of dnf.conf.d drop-ins
+- Fix toString() to not insert [] (RhBug:1584442)
+- Ignore trailing blank lines in config (RhBug:1722493)
+- Fix handling large number of filenames on input (RhBug:1690915)
+- Fix attaching/detaching of libsolvRepo (RhBug:1727343,1727424)
+
+====================
+0.35.1 Release Notes
+====================
+- Skip invalid key files in "/etc/pki/rpm-gpg" with warning (RhBug:1644040)
+- Enable timestamp preserving for downloaded data (RhBug:1688537)
+- Set default to skip_if_unavailable=false (RhBug:1679509)
+- Add configuration option skip_if_unavailable (RhBug:1689931)
+- Fix 'database is locked' error (RhBug:1631533)
+- Replace the 'Failed to synchronize cache' message (RhBug:1712055)
+- Fix 'no such table: main.trans_cmdline' error (RhBug:1596540)
+- Add support of modular FailSafe (RhBug:1623128)
+- Add support of DNF main config file in context; used by PackageKit and microdnf (RhBug:1689331)
+- Exit gpg-agent after repokey import (RhBug:1650266)
+
+====================
+0.33.0 Release Notes
+====================
+- Enhance logging handling
+- Do not log DEBUG messages by default
+- Also add subkeys when adding GPG keys
+- Reintroduce hawkey.Repo (deprecated, for compatibility)
+- [module] Fix swig binding for getModuleDependencies()
+
+====================
+0.31.0 Release Notes
+====================
+- Installroot now requires absolute path
+- Support "_none_" value for repo option "proxy" (RhBug:1680272)
+- Add support for Module advisories
+- Add support for xml:base attribute from primary.xml (RhBug:1691315)
+- Improve detection of Platform ID (RhBug:1688462)
+
+====================
+0.28.1 Release Notes
+====================
+- Return empty query if incorrect reldep (RhBug:1687135)
+- ConfigParser: Improve compatibility with Python ConfigParser and dnf-plugin-spacewalk (RhBug:1692044)
+- ConfigParser: Unify default set of string represenation of boolean values
+- Fix segfault when interrupting dnf process (RhBug:1610456)
+
+====================
+0.28.0 Release Notes
+====================
+- Exclude module pkgs that have conflict (RhBug:1670496)
+- Fix zchunk configuration flags
+- Enhance config parser to preserve order of data, and keep comments and format
+- [history] Allow using :memory: db to avoid disk writes
+- Improve ARM detection
+- Add support for SHA-384
+
+====================
+0.26.0 Release Notes
+====================
+- Enhance modular solver to handle enabled and default module streams differently (RhBug:1648839)
+- Add support of wild cards for modules (RhBug:1644588)
+- Add best as default behavior (RhBug:1671683,1670776)
+
+====================
+0.24.1 Release Notes
+====================
+- Add support for zchunk
+- Enhance LIBDNF plugins support
+- Enhance sorting for module list (RhBug:1590358)
+- [repo] Check whether metadata cache is expired (RhBug:1539620,1648274)
+- [DnfRepo] Add methods for alternative repository metadata type and download (RhBug:1656314)
+- Remove installed profile on module enable or disable (RhBug:1653623)
+- [sack] Implement dnf_sack_get_rpmdb_version()
+
+====================
+0.22.3 Release Notes
+====================
+- Modify solver_describe_decision to report cleaned (RhBug:1486749)
+- [swdb] create persistent WAL files (RhBug:1640235)
+- Relocate ModuleContainer save hook (RhBug:1632518)
+- [transaction] Fix transaction item lookup for obsoleted packages (RhBug: 1642796)
+- Fix memory leaks and memory allocations
+- [repo] Possibility to extend downloaded repository metadata
+
+====================
+0.22.0 Release Notes
+====================
+- Fix segfault in repo_internalize_trigger (RhBug:1375895)
+- Change sorting of installonly packages (RhBug:1627685)
+- [swdb] Fixed pattern searching in history db (RhBug:1635542)
+- Check correctly gpg for repomd when refresh is used (RhBug:1636743)
+- [conf] Provide additional VectorString methods for compatibility with Python list.
+- [plugins] add plugin loading and hooks into libdnf
+
+====================
+0.20.0 Release Notes
+====================
+- [module] Report module solver errors
+- [module] Enhance module commands and errors
+- [transaction] Fixed several problems with SWDB
+- Remove unneeded regex URL tests (RhBug:1598336)
+- Allow quoted values in ini files (RhBug:1624056)
+- Filter out not unique set of solver problems (RhBug:1564369)
+- Disable python2 build for Fedora 30+
+
+====================
+0.19.1 Release Notes
+====================
+- Fix compilation errors on gcc-4.8.5
+- [module] Allow module queries on disabled modules
+
+====================
+0.19.0 Release Notes
+====================
+- [query] Reldeps can contain a space char (RhBug:1612462)
+- [transaction] Avoid adding duplicates via Transaction::addItem()
+- Fix compilation errors on gcc-4.8.5
+- [module] Make available ModuleProfile using SWIG
+- [module] Redesign module disable and reset
+
+====================
+0.18.0 Release Notes
+====================
+- [repo] Implement GPG key import
+- [repo] Introduce Repo class replacing dnf.repo.Repo
+- [context] Fix memory corruption in dnf_context
+- [rhsm] Fix: RHSM don't write .repo file with same content (RhBug:1600452)
+- [module] Create /etc/dnf/modules.d if it doesn't exist.
+- [module] Forward C++ exceptions to bindings.
+
+====================
+0.17.2 Release Notes
+====================
+- [sqlite3] Change db locking mode to DEFAULT.
+- [doc] Add libsmartcols-devel to devel deps.
+
+====================
+0.17.1 Release Notes
+====================
+- [module] Solve a problem in python constructor of NSVCAP if no version.
+- [translations] Update translations from zanata.
+- [transaction] Fix crash after using dnf.comps.CompsQuery and forking the process in Anaconda.
+- [module] Support for resetting module state.
+- [output] Introduce wrapper for smartcols.
+
+====================
+0.17.0 Release Notes
+====================
+- [conf] Add module_platform_id option.
+- [module] Add ModulePackageContainer class.
+- [module] Add ModulePersistor class.
+- [sack] Module filtering made available in python API
+- [sack] Module auto-enabling according to installed packages
+
+====================
+0.16.1 Release Notes
+====================
+* Implement 'module_hotfixes' conf option to skip filtering RPMs from hotfix repos.
+* Fix distupgrade filter, allow downgrades.
+* Module dependency resolution
+* Platform pseudo-module based on /etc/os-release
+* Add Goal::listSuggested()
+
+====================
+0.16.0 Release Notes
+====================
+* Fix RHSM plugin
+* Add support for logging
+
+====================
+0.15.2 Release Notes
+====================
+
+Bugs fixed in 0.15.2:
+
+* :rhbug:`1595487`
+
+====================
+0.15.0 Release Notes
+====================
+
+* Filtering rpms by module metadata
+* New SWIG bindings
+* New history database
+* New config classes
+* Query performance improvements
+* New query filter nevra_strict
+
+Bugs fixed in 0.15.0:
+
+* :rhbug:`1498207`
+* :rhbug:`1500361`
+* :rhbug:`1486749`
+* :rhbug:`1525542`
+* :rhbug:`1550030`
+* :rhbug:`1576749`
+* :rhbug:`1537981`
+* :rhbug:`1588443`
+* :rhbug:`1565647`
+
+====================
+0.11.1 Release Notes
+====================
+
+* Improvement query performance
+* Run file query in hy_subject_get_best_solution only for files (arguments that start with ``/`` or ``*/``)
+
+Bugs fixed in 0.11.1:
+
+* :rhbug:`1498207`
+
+====================
+0.10.1 Release Notes
+====================
+
+It improves query performance with ``name`` and ``arch`` filters. Also ``nevra`` filter will now
+handle string with or without ``epoch``.
+Additionally for python bindings it renames ``NEVRA._has_just_name()`` to ``NEVRA.has_just_name()``
+due to movement of code into c part of library.
+
+Bugs fixed in 0.10.1:
+
+* :rhbug:`1260242`
+* :rhbug:`1485881`
+* :rhbug:`1361187`
+
+===================
+0.9.3 Release Notes
+===================
+
+It moves query glob optimization from python code to C part.
+
+Bugs fixed in 0.9.3:
+
+* :rhbug:`1381506`
+* :rhbug:`1464249`
+
+===================
+0.1.7 Release Notes
+===================
+Released: 2014-12-19
+
+Notes:
+ - librepo >= 1.7.11 is now required
+
+New Features:
+ - Add HIF_SOURCE_UPDATE_FLAG_SIMULATE (Richard Hughes)
+ - Add a large number of GPG tests (Richard Hughes)
+ - Add hif_source_get_filename_md() (Richard Hughes)
+ - Add the concept of metadata-only software sources (Richard Hughes)
+ - Support appstream and appstream-icons metadata types (Richard Hughes)
+
+Bugfixes:
+ - Automatically import public keys into the librepo keyring (Richard Hughes)
+ - Call hif_state_set_allow_cancel() when the state is uncancellable (Richard Hughes)
+ - Correctly update sources with baseurls ending with a slash (Richard Hughes)
+ - Don't unref the HifSource when invalidating as this is not threadsafe (Richard Hughes)
+ - Fix crash when parsing the bumblebee.repo file (Richard Hughes)
+ - Improve handling of local metadata (Richard Hughes)
+ - Only set LRO_GPGCHECK when repo_gpgcheck=1 (Richard Hughes)
+
+===================
+0.1.6 Release Notes
+===================
+Released: 2014-11-10
+
+New Features:
+ - Add support for package reinstallation and downgrade (Michal Minar)
+ - Copy the vendor cache if present (Richard Hughes)
+
+Bugfixes:
+ - Allow to get repo loader out of context (Michal Minar)
+ - Ensure created directories are world-readable (Richard Hughes)
+ - Support local repositories (Michal Minar)
+
+===================
+0.1.5 Release Notes
+===================
+Released: 2014-09-22
+
+Bugfixes:
+ - Add all native architectures for ARM and i386 (Richard Hughes)
+ - Check for libQtGui rather than libkde* to detect GUI apps (Kevin Kofler)
+
+===================
+0.1.4 Release Notes
+===================
+Released: 2014-09-12
+
+New Features:
+ - Add hif_source_commit() so we don't rewrite the file for each change (Richard Hughes)
+ - Allow setting the default lock directory (Richard Hughes)
+
+Bugfixes:
+ - Ensure all the required directories exist when setting up the context (Richard Hughes)
+ - Use a real path for hy_sack_create() (Richard Hughes)
+
+===================
+0.1.3 Release Notes
+===================
+Released: 2014-09-01
+
+Bugfixes:
+ - Add an error path for when the sources are not valid (Richard Hughes)
+ - Do not call hif_context_setup_sack() automatically (Richard Hughes)
+ - Don't error out for missing treeinfo files (Kalev Lember)
+ - Fix a logic error to fix refreshing with HIF_SOURCE_UPDATE_FLAG_FORCE (Richard Hughes)
+
+===================
+0.1.2 Release Notes
+===================
+Released: 2014-07-17
+
+Notes:
+
+New Features:
+ - Add HifContext accessor in -private for HifState (Colin Walters)
+ - Improve rpm callback handling for packages in the cleanup state (Kalev Lember)
+
+Bugfixes:
+ - Add name of failing repository (Colin Walters)
+ - Create an initial sack in HifContext (Colin Walters)
+ - Error if we can't find any package matching provided name (Colin Walters)
+ - Fix a mixup of HifStateAction and HifPackageInfo (Kalev Lember)
+ - Only set librepo option if value is set (Colin Walters)
+ - Respect install root for rpmdb Packages monitor (Colin Walters)
+ - Update Makefile.am (Elan Ruusamäe)
+
+===================
+0.1.1 Release Notes
+===================
+Released: 2014-06-23
+
+New Features:
+ - Only add system repository if it exists (Colin Walters)
+
+Bugfixes:
+ - Add private accessors for goal/sack (Colin Walters)
+ - Fix a potential crash when removing software (Richard Hughes)
+ - Pass install root to hawkey (Colin Walters)
+
+===================
+0.1.0 Release Notes
+===================
+Released: 2014-06-10
+
+Notes:
+ - This is the first release of a simple library that uses librepo and hawkey
+ to do some high level package management tasks.
+ - libhif is not 100% API or ABI stable yet.
+
+New Features:
+ - Add HifContext as a high level operation (Richard Hughes)
+
+Bugfixes:
+ - Add several g-i annotations (Colin Walters)
+ - Correctly set the cleanup status (Kalev Lember)
+ - Fix a crash when using hif_source_set_keyfile_data() (Richard Hughes)
+ - Use GLib version macros to pin to 2.36 by default (Colin Walters)
--- /dev/null
+if(WITH_SANITIZERS)
+ INSTALL (FILES "dnf-sanitizers.sh" DESTINATION /etc/profile.d/)
+endif()
--- /dev/null
+function dnf {
+ ASAN_OPTIONS=verify_asan_link_order=0 /usr/bin/dnf "$@"
+}
+
+export -f dnf
--- /dev/null
+%global libsolv_version 0.7.21
+%global libmodulemd_version 2.13.0
+%global librepo_version 1.15.0
+%global dnf_conflict 4.11.0
+%global swig_version 3.0.12
+%global libdnf_major_version 0
+%global libdnf_minor_version 73
+%global libdnf_micro_version 2
+
+%define __cmake_in_source_build 1
+
+# set sphinx package name according to distro
+%global requires_python2_sphinx python2-sphinx
+%global requires_python3_sphinx python3-sphinx
+%if 0%{?rhel} == 7
+ %global requires_python2_sphinx python-sphinx
+%endif
+%if 0%{?suse_version}
+ %global requires_python2_sphinx python2-Sphinx
+ %global requires_python3_sphinx python3-Sphinx
+%endif
+
+%bcond_with valgrind
+
+# Do not build bindings for python3 for RHEL <= 7
+%if 0%{?rhel} && 0%{?rhel} <= 7
+%bcond_with python3
+%else
+%bcond_without python3
+%endif
+
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
+# Disable python2 build by default
+%bcond_with python2
+%else
+%bcond_without python2
+%endif
+
+%if 0%{?rhel} && ! 0%{?centos}
+%bcond_without rhsm
+%else
+%bcond_with rhsm
+%endif
+
+%if 0%{?rhel}
+%bcond_with zchunk
+%else
+%bcond_without zchunk
+%endif
+
+%bcond_with sanitizers
+
+%global _cmake_opts \\\
+ -DENABLE_RHSM_SUPPORT=%{?with_rhsm:ON}%{!?with_rhsm:OFF} \\\
+ %{nil}
+
+Name: libdnf
+Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version}
+Release: 1%{?dist}
+Summary: Library providing simplified C and Python API to libsolv
+License: LGPL-2.1-or-later
+URL: https://github.com/rpm-software-management/libdnf
+Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz
+
+BuildRequires: cmake
+BuildRequires: gcc
+BuildRequires: gcc-c++
+BuildRequires: libsolv-devel >= %{libsolv_version}
+BuildRequires: pkgconfig(librepo) >= %{librepo_version}
+BuildRequires: pkgconfig(check)
+%if %{with valgrind}
+BuildRequires: valgrind
+%endif
+BuildRequires: pkgconfig(gio-unix-2.0) >= 2.46.0
+BuildRequires: pkgconfig(gtk-doc)
+BuildRequires: rpm-devel >= 4.15.0
+%if %{with rhsm}
+BuildRequires: pkgconfig(librhsm) >= 0.0.3
+%endif
+%if %{with zchunk}
+BuildRequires: pkgconfig(zck) >= 0.9.11
+%endif
+BuildRequires: pkgconfig(sqlite3)
+BuildRequires: pkgconfig(json-c)
+BuildRequires: pkgconfig(cppunit)
+BuildRequires: pkgconfig(modulemd-2.0) >= %{libmodulemd_version}
+BuildRequires: pkgconfig(smartcols)
+BuildRequires: gettext
+
+%if %{with sanitizers}
+BuildRequires: libasan
+BuildRequires: liblsan
+BuildRequires: libubsan
+%endif
+
+Requires: libmodulemd%{?_isa} >= %{libmodulemd_version}
+Requires: libsolv%{?_isa} >= %{libsolv_version}
+Requires: librepo%{?_isa} >= %{librepo_version}
+
+%if %{without python2}
+# Obsoleted from here so we can track the fast growing version easily.
+# We intentionally only obsolete and not provide, this is a broken upgrade
+# prevention, not providing the removed functionality.
+Obsoletes: python2-%{name} < %{version}-%{release}
+Obsoletes: python2-hawkey < %{version}-%{release}
+Obsoletes: python2-hawkey-debuginfo < %{version}-%{release}
+Obsoletes: python2-libdnf-debuginfo < %{version}-%{release}
+%endif
+
+%description
+A Library providing simplified C and Python API to libsolv.
+
+%package devel
+Summary: Development files for %{name}
+Requires: %{name}%{?_isa} = %{version}-%{release}
+Requires: libsolv-devel%{?_isa} >= %{libsolv_version}
+
+%description devel
+Development files for %{name}.
+
+%if %{with python2}
+%package -n python2-%{name}
+%{?python_provide:%python_provide python2-%{name}}
+Summary: Python 2 bindings for the libdnf library.
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: python2-devel
+%if !0%{?mageia}
+BuildRequires: %{requires_python2_sphinx}
+%endif
+%if 0%{?rhel} == 7
+BuildRequires: swig3 >= %{swig_version}
+%else
+BuildRequires: swig >= %{swig_version}
+%endif
+
+%description -n python2-%{name}
+Python 2 bindings for the libdnf library.
+%endif
+# endif with python2
+
+%if %{with python3}
+%package -n python3-%{name}
+%{?python_provide:%python_provide python3-%{name}}
+Summary: Python 3 bindings for the libdnf library.
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: python3-devel
+BuildRequires: %{requires_python3_sphinx}
+BuildRequires: swig >= %{swig_version}
+
+%description -n python3-%{name}
+Python 3 bindings for the libdnf library.
+%endif
+
+%if %{with python2}
+%package -n python2-hawkey
+Summary: Python 2 bindings for the hawkey library
+%{?python_provide:%python_provide python2-hawkey}
+BuildRequires: python2-devel
+Requires: %{name}%{?_isa} = %{version}-%{release}
+Requires: python2-%{name} = %{version}-%{release}
+# Fix problem with hawkey - dnf version incompatibility
+# Can be deleted for distros where only python2-dnf >= 2.0.0
+Conflicts: python2-dnf < %{dnf_conflict}
+Conflicts: python-dnf < %{dnf_conflict}
+
+%description -n python2-hawkey
+Python 2 bindings for the hawkey library.
+%endif
+# endif with python2
+
+%if %{with python3}
+%package -n python3-hawkey
+Summary: Python 3 bindings for the hawkey library
+%{?python_provide:%python_provide python3-hawkey}
+BuildRequires: python3-devel
+Requires: %{name}%{?_isa} = %{version}-%{release}
+Requires: python3-%{name} = %{version}-%{release}
+# Fix problem with hawkey - dnf version incompatibility
+# Can be deleted for distros where only python3-dnf >= 2.0.0
+Conflicts: python3-dnf < %{dnf_conflict}
+# Obsoletes F27 packages
+Obsoletes: platform-python-hawkey < %{version}-%{release}
+
+%description -n python3-hawkey
+Python 3 bindings for the hawkey library.
+%endif
+
+%prep
+%autosetup
+%if %{with python2}
+mkdir build-py2
+%endif
+%if %{with python3}
+mkdir build-py3
+%endif
+
+%build
+%if %{with python2}
+pushd build-py2
+ %if 0%{?mageia} || 0%{?suse_version}
+ cd ..
+ %define _cmake_builddir build-py2
+ %define __builddir build-py2
+ %endif
+ %cmake -DPYTHON_DESIRED:FILEPATH=%{__python2} -DWITH_MAN=OFF ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \
+ -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF}
+ %make_build
+popd
+%endif
+# endif with python2
+
+%if %{with python3}
+pushd build-py3
+ %if 0%{?mageia} || 0%{?suse_version}
+ cd ..
+ %define _cmake_builddir build-py3
+ %define __builddir build-py3
+ %endif
+ %cmake -DPYTHON_DESIRED:FILEPATH=%{__python3} -DWITH_GIR=0 -DWITH_MAN=0 -Dgtkdoc=0 ../ %{!?with_zchunk:-DWITH_ZCHUNK=OFF} %{!?with_valgrind:-DDISABLE_VALGRIND=1} %{_cmake_opts} -DLIBDNF_MAJOR_VERSION=%{libdnf_major_version} -DLIBDNF_MINOR_VERSION=%{libdnf_minor_version} -DLIBDNF_MICRO_VERSION=%{libdnf_micro_version} \
+ -DWITH_SANITIZERS=%{?with_sanitizers:ON}%{!?with_sanitizers:OFF}
+ %make_build
+popd
+%endif
+
+%check
+%if %{with python2}
+pushd build-py2
+ make ARGS="-V" test
+popd
+%endif
+%if %{with python3}
+# If we didn't run the general tests yet, do it now.
+%if %{without python2}
+pushd build-py3
+ make ARGS="-V" test
+popd
+%else
+# Otherwise, run just the Python tests, not all of
+# them, since we have coverage of the core from the
+# first build
+pushd build-py3/python/hawkey/tests
+ make ARGS="-V" test
+popd
+%endif
+%endif
+
+%install
+%if %{with python2}
+pushd build-py2
+ %make_install
+popd
+%endif
+%if %{with python3}
+pushd build-py3
+ %make_install
+popd
+%endif
+
+%find_lang %{name}
+
+%if (0%{?rhel} && 0%{?rhel} <= 7) || 0%{?suse_version}
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+%else
+%ldconfig_scriptlets
+%endif
+
+%files -f %{name}.lang
+%license COPYING
+%doc README.md AUTHORS
+%{_libdir}/%{name}.so.*
+%dir %{_libdir}/libdnf/
+%dir %{_libdir}/libdnf/plugins/
+%{_libdir}/libdnf/plugins/README
+%if %{with sanitizers}
+%{_sysconfdir}/profile.d/dnf-sanitizers.sh
+%endif
+
+%files devel
+%doc %{_datadir}/gtk-doc/html/%{name}/
+%{_libdir}/%{name}.so
+%{_libdir}/pkgconfig/%{name}.pc
+%{_includedir}/%{name}/
+
+%if %{with python2}
+%files -n python2-%{name}
+%{python2_sitearch}/%{name}/
+%endif
+
+%if %{with python3}
+%files -n python3-%{name}
+%{python3_sitearch}/%{name}-*.dist-info
+%{python3_sitearch}/%{name}/
+%endif
+
+%if %{with python2}
+%files -n python2-hawkey
+%{python2_sitearch}/hawkey/
+%endif
+
+%if %{with python3}
+%files -n python3-hawkey
+%{python3_sitearch}/hawkey/
+%endif
+
+%changelog
--- /dev/null
+set(LIBDNF_SRCS
+ dnf-advisorypkg.cpp
+ dnf-advisoryref.cpp
+ dnf-advisory.cpp
+ hy-goal.cpp
+ hy-iutil.cpp
+ log.cpp
+ nevra.cpp
+ nsvcap.cpp
+ dnf-reldep.cpp
+ dnf-reldep-list.cpp
+ hy-package.cpp
+ hy-packageset.cpp
+ hy-query.cpp
+ dnf-sack.cpp
+ hy-selector.cpp
+ hy-subject.cpp
+ hy-util.cpp
+ dnf-db.cpp
+ dnf-conf.cpp
+ dnf-context.cpp
+ dnf-goal.cpp
+ dnf-keyring.cpp
+ dnf-lock.cpp
+ dnf-package.cpp
+ dnf-packagedelta.cpp
+ dnf-repo-loader.cpp
+ dnf-rpmts.cpp
+ dnf-repo.cpp
+ dnf-state.cpp
+ dnf-transaction.cpp
+ dnf-utils.cpp
+)
+
+include_directories(transaction)
+add_subdirectory("transaction")
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(MULTILIB_ARCH "64")
+ configure_file("config-64.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/config-64.h)
+elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(MULTILIB_ARCH "32")
+ configure_file("config-64.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/config-32.h)
+endif()
+configure_file("dnf-version.h.in" ${CMAKE_CURRENT_SOURCE_DIR}/dnf-version.h)
+configure_file("libdnf.pc.in" ${CMAKE_CURRENT_BINARY_DIR}/libdnf.pc @ONLY)
+
+add_subdirectory(goal)
+add_subdirectory(repo)
+add_subdirectory(module)
+add_subdirectory(utils)
+add_subdirectory(conf)
+add_subdirectory(sack)
+add_subdirectory(plugin)
+
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${GOAL_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${MODULE_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${UTILS_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${CONF_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${SACK_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${REPO_SOURCES})
+set(LIBDNF_SRCS ${LIBDNF_SRCS} ${PLUGIN_SOURCES})
+
+if(ENABLE_STATIC)
+ add_library(libdnf STATIC ${LIBDNF_SRCS})
+else()
+ add_library(libdnf SHARED ${LIBDNF_SRCS})
+endif()
+target_link_libraries(libdnf
+ ${CMAKE_DL_LIBS}
+ ${REPO_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${GLIB_GOBJECT_LIBRARIES}
+ ${GLIB_GIO_LIBRARIES}
+ ${GLIB_GIO_UNIX_LIBRARIES}
+ ${LIBSOLV_LIBRARY}
+ ${LIBSOLV_EXT_LIBRARY}
+ ${RPM_LIBRARIES}
+ ${SCOLS_LIBRARIES}
+ ${SQLite3_LIBRARIES}
+ ${JSONC_LIBRARIES}
+ ${LIBMODULEMD_LIBRARIES}
+ ${SMARTCOLS_LIBRARIES}
+)
+
+if(ENABLE_RHSM_SUPPORT)
+ target_link_libraries(libdnf ${RHSM_LIBRARIES})
+endif()
+
+set(DNF_SO_VERSION 2)
+set_target_properties(libdnf PROPERTIES OUTPUT_NAME "dnf")
+set_target_properties(libdnf PROPERTIES SOVERSION ${DNF_SO_VERSION})
+
+set(LIBHAWKEY_headers
+ hy-goal.h
+ hy-nevra.h
+ hy-package.h
+ hy-packageset.h
+ hy-query.h
+ hy-repo.h
+ hy-selector.h
+ hy-subject.h
+ hy-types.h
+ hy-util.h
+)
+
+set(LIBDNF_headers
+ config.h
+ log.hpp
+ nevra.hpp
+ nsvcap.hpp
+ dnf-advisory.h
+ dnf-advisorypkg.h
+ dnf-advisoryref.h
+ dnf-db.h
+ dnf-conf.h
+ dnf-context.h
+ dnf-enums.h
+ dnf-goal.h
+ dnf-keyring.h
+ dnf-lock.h
+ dnf-package.h
+ dnf-packagedelta.h
+ dnf-repo-loader.h
+ dnf-rpmts.h
+ dnf-sack.h
+ dnf-reldep.h
+ dnf-reldep-list.h
+ dnf-repo.h
+ dnf-state.h
+ dnf-transaction.h
+ dnf-types.h
+ dnf-utils.h
+ dnf-version.h
+ libdnf.h
+)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libdnf.pc
+ DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig
+)
+install(FILES ${LIBDNF_headers} DESTINATION include/libdnf)
+install(FILES ${LIBHAWKEY_headers} DESTINATION include/libdnf)
+install(TARGETS libdnf LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
+install(FILES "README.plugins" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/libdnf/plugins" RENAME "README")
--- /dev/null
+
+This directory holds plugins for the libdnf library.
+Any files in this directory which have the ".so" extension will be
+processed as libdnf plugins.
+
+Files are processed in alphabetical order.
--- /dev/null
+#ifndef LIBDNF_CATCH_ERROR_HPP
+#define LIBDNF_CATCH_ERROR_HPP
+
+#include "error.hpp"
+#include "goal/Goal.hpp"
+
+#include <glib.h>
+
+
+#define CATCH_TO_GERROR(RET) \
+catch (const libdnf::Goal::Error& e) { \
+ g_set_error_literal(error, DNF_ERROR, e.getErrCode(), e.what()); \
+ return RET; \
+} catch (const libdnf::Error& e) { \
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, e.what()); \
+ return RET; \
+}
+
+#endif
--- /dev/null
+set(CONF_SOURCES
+ ${CONF_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionBool.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionEnum.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionNumber.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionPath.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionSeconds.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionString.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionStringList.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionBinds.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigMain.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigRepo.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigParser.cpp
+ PARENT_SCOPE
+)
+
+set(CONF_PUBLIC_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/Option.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionChild.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionBool.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionEnum.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionNumber.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionPath.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionSeconds.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionString.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionStringList.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/OptionBinds.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Config.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigMain.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigRepo.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigParser.hpp
+)
+
+install(FILES ${CONF_PUBLIC_HEADERS} DESTINATION include/libdnf/conf)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_PRIVATE_HPP
+#define _LIBDNF_CONFIG_PRIVATE_HPP
+
+#include "Option.hpp"
+
+namespace libdnf {
+
+template<typename T>
+static void optionTListAppend(T & option, Option::Priority priority, const std::string & value)
+{
+ if (value.empty()) {
+ option.set(priority, value);
+ return;
+ }
+ auto addPriority = priority < option.getPriority() ? option.getPriority() : priority;
+ auto val = option.fromString(value);
+ bool first = true;
+ for (auto & item : val) {
+ if (item.empty()) {
+ if (first) {
+ option.set(priority, item);
+ }
+ } else {
+ auto origValue = option.getValue();
+ origValue.push_back(item);
+ option.set(addPriority, origValue);
+ }
+ first = false;
+ }
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_HPP
+#define _LIBDNF_CONFIG_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "OptionBinds.hpp"
+
+namespace libdnf {
+
+class Config {
+public:
+ OptionBinds & optBinds() { return binds; }
+
+private:
+ OptionBinds binds;
+};
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ConfigMain.hpp"
+#include "Const.hpp"
+#include "Config-private.hpp"
+#include "libdnf/utils/os-release.hpp"
+#include "utils.hpp"
+
+#include <algorithm>
+#include <array>
+#include <cctype>
+#include <istream>
+#include <ostream>
+#include <fstream>
+#include <utility>
+
+#include <dirent.h>
+#include <glob.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+extern char **environ;
+
+namespace libdnf {
+
+/**
+* @brief Converts a friendly bandwidth option to bytes
+*
+* Function converts a friendly bandwidth option to bytes. The input
+* should be a string containing a (possibly floating point)
+* number followed by an optional single character unit. Valid
+* units are 'k', 'M', 'G'. Case is ignored. The convention that
+* 1k = 1024 bytes is used.
+*
+* @param str Bandwidth as user friendly string
+* @return int Number of bytes
+*/
+static int strToBytes(const std::string & str)
+{
+ if (str.empty())
+ throw Option::InvalidValue(_("no value specified"));
+
+ std::size_t idx;
+ auto res = std::stod(str, &idx);
+ if (res < 0)
+ throw Option::InvalidValue(tfm::format(_("seconds value '%s' must not be negative"), str));
+
+ if (idx < str.length()) {
+ if (idx < str.length() - 1)
+ throw Option::InvalidValue(tfm::format(_("could not convert '%s' to bytes"), str));
+ switch (str.back()) {
+ case 'k': case 'K':
+ res *= 1024;
+ break;
+ case 'm': case 'M':
+ res *= 1024 * 1024;
+ break;
+ case 'g': case 'G':
+ res *= 1024 * 1024 * 1024;
+ break;
+ default:
+ throw Option::InvalidValue(tfm::format(_("unknown unit '%s'"), str.back()));
+ }
+ }
+
+ return res;
+}
+
+static void addFromFile(std::ostream & out, const std::string & filePath)
+{
+ std::ifstream ifs(filePath);
+ if (!ifs)
+ throw std::runtime_error("addFromFile(): Can't open file");
+ ifs.exceptions(std::ifstream::badbit);
+
+ std::string line;
+ while (!ifs.eof()) {
+ std::getline(ifs, line);
+ auto start = line.find_first_not_of(" \t\r");
+ if (start == std::string::npos)
+ continue;
+ if (line[start] == '#')
+ continue;
+ auto end = line.find_last_not_of(" \t\r");
+
+ out.write(line.c_str()+start, end - start + 1);
+ out.put(' ');
+ }
+}
+
+static void addFromFiles(std::ostream & out, const std::string & globPath)
+{
+ glob_t globBuf;
+ glob(globPath.c_str(), GLOB_MARK | GLOB_NOSORT, NULL, &globBuf);
+ for (size_t i = 0; i < globBuf.gl_pathc; ++i) {
+ auto path = globBuf.gl_pathv[i];
+ if (path[strlen(path)-1] != '/')
+ addFromFile(out, path);
+ }
+ globfree(&globBuf);
+}
+
+/**
+* @brief Replaces globs (like /etc/foo.d/\\*.foo) by content of matching files.
+*
+* Ignores comment lines (start with '#') and blank lines in files.
+* Result:
+* Words delimited by spaces. Characters ',' and '\n' are replaced by spaces.
+* Extra spaces are removed.
+* @param strWithGlobs Input string with globs
+* @return Words delimited by space
+*/
+static std::string resolveGlobs(const std::string & strWithGlobs)
+{
+ std::ostringstream res;
+ std::string::size_type start{0};
+ while (start < strWithGlobs.length()) {
+ auto end = strWithGlobs.find_first_of(" ,\n", start);
+ if (strWithGlobs.compare(start, 5, "glob:") == 0) {
+ start += 5;
+ if (start >= strWithGlobs.length())
+ break;
+ if (end == std::string::npos) {
+ addFromFiles(res, strWithGlobs.substr(start));
+ break;
+ }
+ if (end - start != 0)
+ addFromFiles(res, strWithGlobs.substr(start, end - start));
+ } else {
+ if (end == std::string::npos) {
+ res << strWithGlobs.substr(start);
+ break;
+ }
+ if (end - start != 0)
+ res << strWithGlobs.substr(start, end - start) << " ";
+ }
+ start = end + 1;
+ }
+ return res.str();
+}
+
+class ConfigMain::Impl {
+ friend class ConfigMain;
+
+ Impl(Config & owner);
+
+ Config & owner;
+
+ OptionNumber<std::int32_t> debuglevel{2, 0, 10};
+ OptionNumber<std::int32_t> errorlevel{3, 0, 10};
+ OptionNumber<std::int32_t> logfilelevel{9, 0, 10};
+ OptionPath installroot{"/", false, true};
+ OptionPath config_file_path{CONF_FILENAME};
+ OptionBool plugins{true};
+ OptionStringList pluginpath{std::vector<std::string>{}};
+ OptionStringList pluginconfpath{std::vector<std::string>{}};
+ OptionPath persistdir{PERSISTDIR};
+ OptionBool transformdb{true};
+ OptionNumber<std::int32_t> recent{7, 0};
+ OptionBool reset_nice{true};
+ OptionPath system_cachedir{SYSTEM_CACHEDIR};
+ OptionBool cacheonly{false};
+ OptionBool keepcache{false};
+ OptionString logdir{"/var/log"};
+ OptionNumber<std::int32_t> log_size{1024 * 1024, strToBytes};
+ OptionNumber<std::int32_t> log_rotate{4, 0};
+ OptionBool log_compress{false};
+ OptionStringList varsdir{VARS_DIRS};
+ OptionStringList reposdir{{"/etc/yum.repos.d", "/etc/yum/repos.d", "/etc/distro.repos.d"}};
+ OptionBool debug_solver{false};
+ OptionStringList installonlypkgs{INSTALLONLYPKGS};
+ OptionStringList group_package_types{GROUP_PACKAGE_TYPES};
+ OptionStringList optional_metadata_types{std::vector<std::string>{}};
+
+ OptionNumber<std::uint32_t> installonly_limit{3, 0,
+ [](const std::string & value)->std::uint32_t{
+ if (value == "<off>")
+ return 0;
+ std::int32_t value_i;
+ try {
+ value_i = std::stol(value);
+ }
+ catch (...) {
+ throw Option::InvalidValue(tfm::format(_("invalid value")));
+ }
+ if (value_i == 1)
+ throw Option::InvalidValue(tfm::format(_("value 1 is not allowed")));
+ if (value_i < 0)
+ throw Option::InvalidValue(tfm::format(_("negative value is not allowed")));
+ return (std::uint32_t)value_i;
+ }
+ };
+
+ OptionStringList tsflags{std::vector<std::string>{}};
+ OptionBool assumeyes{false};
+ OptionBool assumeno{false};
+ OptionBool check_config_file_age{true};
+ OptionBool defaultyes{false};
+ OptionBool diskspacecheck{true};
+ OptionBool localpkg_gpgcheck{false};
+ OptionBool gpgkey_dns_verification{false};
+ OptionBool obsoletes{true};
+ OptionBool showdupesfromrepos{false};
+ OptionBool exit_on_lock{false};
+ OptionBool allow_vendor_change{true};
+ OptionSeconds metadata_timer_sync{60 * 60 * 3}; // 3 hours
+ OptionStringList disable_excludes{std::vector<std::string>{}};
+ OptionEnum<std::string> multilib_policy{"best", {"best", "all"}}; // :api
+ OptionBool best{false}; // :api
+ OptionBool install_weak_deps{true};
+ OptionString bugtracker_url{BUGTRACKER};
+ OptionBool zchunk{true};
+
+ OptionEnum<std::string> color{"auto", {"auto", "never", "always"},
+ [](const std::string & value){
+ const std::array<const char *, 4> always{{"on", "yes", "1", "true"}};
+ const std::array<const char *, 4> never{{"off", "no", "0", "false"}};
+ const std::array<const char *, 2> aut{{"tty", "if-tty"}};
+ std::string tmp;
+ if (std::find(always.begin(), always.end(), value) != always.end())
+ tmp = "always";
+ else if (std::find(never.begin(), never.end(), value) != never.end())
+ tmp = "never";
+ else if (std::find(aut.begin(), aut.end(), value) != aut.end())
+ tmp = "auto";
+ else
+ tmp = value;
+ return tmp;
+ }
+ };
+
+ OptionString color_list_installed_older{"yellow"};
+ OptionString color_list_installed_newer{"bold,yellow"};
+ OptionString color_list_installed_reinstall{"cyan"};
+ OptionString color_list_installed_extra{"bold,red"};
+ OptionString color_list_available_upgrade{"bold,blue"};
+ OptionString color_list_available_downgrade{"magenta"};
+ OptionString color_list_available_reinstall{"bold,underline,green"};
+ OptionString color_list_available_install{"bold,cyan"};
+ OptionString color_update_installed{"red"};
+ OptionString color_update_local{"green"};
+ OptionString color_update_remote{"bold,green"};
+ OptionString color_search_match{"bold,magenta"};
+ OptionBool history_record{true};
+ OptionStringList history_record_packages{std::vector<std::string>{"dnf", "rpm"}};
+ OptionString rpmverbosity{"info"};
+ OptionBool strict{true}; // :api
+ OptionBool skip_broken{false}; // :yum-compatibility
+ OptionBool autocheck_running_kernel{true}; // :yum-compatibility
+ OptionBool clean_requirements_on_remove{true};
+
+ OptionEnum<std::string> history_list_view{"commands", {"single-user-commands", "users", "commands"},
+ [](const std::string & value){
+ if (value == "cmds" || value == "default")
+ return std::string("commands");
+ else
+ return value;
+ }
+ };
+
+ OptionBool upgrade_group_objects_upgrade{true}; // :api
+ OptionPath destdir{nullptr};
+ OptionString comment{nullptr};
+ OptionBool downloadonly{false}; // runtime only option
+ OptionBool ignorearch{false};
+ OptionString module_platform_id{nullptr};
+ OptionBool module_stream_switch{false};
+ OptionBool module_obsoletes{false};
+
+ OptionString user_agent{getUserAgent()};
+ OptionBool countme{false};
+ OptionBool protect_running_kernel{true};
+
+ // Repo main config
+
+ OptionNumber<std::uint32_t> retries{10};
+ OptionString cachedir{nullptr};
+ OptionBool fastestmirror{false};
+ OptionStringList excludepkgs{std::vector<std::string>{}};
+ OptionStringList includepkgs{std::vector<std::string>{}};
+ OptionStringList exclude_from_weak{std::vector<std::string>{}};
+ OptionBool exclude_from_weak_autodetect{true};
+ OptionString proxy{""};
+ OptionString proxy_username{nullptr};
+ OptionString proxy_password{nullptr};
+
+ OptionEnum<std::string> proxy_auth_method{"any", {"any", "none", "basic", "digest",
+ "negotiate", "ntlm", "digest_ie", "ntlm_wb"},
+ [](const std::string & value){
+ auto tmp = value;
+ std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
+ return tmp;
+ }
+ };
+
+ OptionStringList protected_packages{resolveGlobs("dnf " \
+ "glob:/etc/yum/protected.d/*.conf " \
+ "glob:/etc/dnf/protected.d/*.conf")};
+ OptionString username{""};
+ OptionString password{""};
+ OptionBool gpgcheck{false};
+ OptionBool repo_gpgcheck{false};
+ OptionBool enabled{true};
+ OptionBool enablegroups{true};
+ OptionNumber<std::uint32_t> bandwidth{0, strToBytes};
+ OptionNumber<std::uint32_t> minrate{1000, strToBytes};
+
+ OptionEnum<std::string> ip_resolve{"whatever", {"ipv4", "ipv6", "whatever"},
+ [](const std::string & value){
+ auto tmp = value;
+ if (value == "4") tmp = "ipv4";
+ else if (value == "6") tmp = "ipv6";
+ else std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
+ return tmp;
+ }
+ };
+
+ OptionNumber<float> throttle{0, 0,
+ [](const std::string & value)->float{
+ if (!value.empty() && value.back()=='%') {
+ std::size_t idx;
+ auto res = std::stod(value, &idx);
+ if (res < 0 || res > 100)
+ throw Option::InvalidValue(tfm::format(_("percentage '%s' is out of range"), value));
+ return res/100;
+ }
+ return strToBytes(value);
+ }
+ };
+
+ OptionSeconds timeout{30};
+ OptionNumber<std::uint32_t> max_parallel_downloads{3, 1};
+ OptionNumber<std::uint32_t> max_downloads_per_mirror{3, 1};
+ OptionSeconds metadata_expire{60 * 60 * 48};
+ OptionString sslcacert{""};
+ OptionBool sslverify{true};
+ OptionString sslclientcert{""};
+ OptionString sslclientkey{""};
+ OptionString proxy_sslcacert{""};
+ OptionBool proxy_sslverify{true};
+ OptionString proxy_sslclientcert{""};
+ OptionString proxy_sslclientkey{""};
+ OptionBool deltarpm{false};
+ OptionNumber<std::uint32_t> deltarpm_percentage{75};
+ OptionBool skip_if_unavailable{false};
+ OptionBool sslverifystatus{false};
+};
+
+ConfigMain::Impl::Impl(Config & owner)
+: owner(owner)
+{
+ owner.optBinds().add("debuglevel", debuglevel);
+ owner.optBinds().add("errorlevel", errorlevel);
+ owner.optBinds().add("logfilelevel", logfilelevel);
+ owner.optBinds().add("installroot", installroot);
+ owner.optBinds().add("config_file_path", config_file_path);
+ owner.optBinds().add("plugins", plugins);
+ owner.optBinds().add("pluginpath", pluginpath);
+ owner.optBinds().add("pluginconfpath", pluginconfpath);
+ owner.optBinds().add("persistdir", persistdir);
+ owner.optBinds().add("transformdb", transformdb);
+ owner.optBinds().add("recent", recent);
+ owner.optBinds().add("reset_nice", reset_nice);
+ owner.optBinds().add("system_cachedir", system_cachedir);
+ owner.optBinds().add("cacheonly", cacheonly);
+ owner.optBinds().add("keepcache", keepcache);
+ owner.optBinds().add("logdir", logdir);
+ owner.optBinds().add("log_size", log_size);
+ owner.optBinds().add("log_rotate", log_rotate);
+ owner.optBinds().add("log_compress", log_compress);
+ owner.optBinds().add("varsdir", varsdir);
+ owner.optBinds().add("reposdir", reposdir);
+ owner.optBinds().add("debug_solver", debug_solver);
+
+ owner.optBinds().add("installonlypkgs", installonlypkgs,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(installonlypkgs, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("group_package_types", group_package_types);
+ owner.optBinds().add("optional_metadata_types", optional_metadata_types);
+ owner.optBinds().add("installonly_limit", installonly_limit);
+
+ owner.optBinds().add("tsflags", tsflags,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(tsflags, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("assumeyes", assumeyes);
+ owner.optBinds().add("assumeno", assumeno);
+ owner.optBinds().add("check_config_file_age", check_config_file_age);
+ owner.optBinds().add("defaultyes", defaultyes);
+ owner.optBinds().add("diskspacecheck", diskspacecheck);
+ owner.optBinds().add("localpkg_gpgcheck", localpkg_gpgcheck);
+ owner.optBinds().add("gpgkey_dns_verification", gpgkey_dns_verification);
+ owner.optBinds().add("obsoletes", obsoletes);
+ owner.optBinds().add("showdupesfromrepos", showdupesfromrepos);
+ owner.optBinds().add("exit_on_lock", exit_on_lock);
+ owner.optBinds().add("allow_vendor_change", allow_vendor_change);
+ owner.optBinds().add("metadata_timer_sync", metadata_timer_sync);
+ owner.optBinds().add("disable_excludes", disable_excludes);
+ owner.optBinds().add("multilib_policy", multilib_policy);
+ owner.optBinds().add("best", best);
+ owner.optBinds().add("install_weak_deps", install_weak_deps);
+ owner.optBinds().add("bugtracker_url", bugtracker_url);
+ owner.optBinds().add("zchunk", zchunk);
+ owner.optBinds().add("color", color);
+ owner.optBinds().add("color_list_installed_older", color_list_installed_older);
+ owner.optBinds().add("color_list_installed_newer", color_list_installed_newer);
+ owner.optBinds().add("color_list_installed_reinstall", color_list_installed_reinstall);
+ owner.optBinds().add("color_list_installed_extra", color_list_installed_extra);
+ owner.optBinds().add("color_list_available_upgrade", color_list_available_upgrade);
+ owner.optBinds().add("color_list_available_downgrade", color_list_available_downgrade);
+ owner.optBinds().add("color_list_available_reinstall", color_list_available_reinstall);
+ owner.optBinds().add("color_list_available_install", color_list_available_install);
+ owner.optBinds().add("color_update_installed", color_update_installed);
+ owner.optBinds().add("color_update_local", color_update_local);
+ owner.optBinds().add("color_update_remote", color_update_remote);
+ owner.optBinds().add("color_search_match", color_search_match);
+ owner.optBinds().add("history_record", history_record);
+ owner.optBinds().add("history_record_packages", history_record_packages);
+ owner.optBinds().add("rpmverbosity", rpmverbosity);
+ owner.optBinds().add("strict", strict);
+ owner.optBinds().add("skip_broken", skip_broken);
+ owner.optBinds().add("autocheck_running_kernel", autocheck_running_kernel);
+ owner.optBinds().add("clean_requirements_on_remove", clean_requirements_on_remove);
+ owner.optBinds().add("history_list_view", history_list_view);
+ owner.optBinds().add("upgrade_group_objects_upgrade", upgrade_group_objects_upgrade);
+ owner.optBinds().add("destdir", destdir);
+ owner.optBinds().add("comment", comment);
+ owner.optBinds().add("ignorearch", ignorearch);
+ owner.optBinds().add("module_platform_id", module_platform_id);
+ owner.optBinds().add("module_stream_switch", module_stream_switch);
+ owner.optBinds().add("module_obsoletes", module_obsoletes);
+ owner.optBinds().add("user_agent", user_agent);
+ owner.optBinds().add("countme", countme);
+ owner.optBinds().add("protect_running_kernel", protect_running_kernel);
+
+ // Repo main config
+
+ owner.optBinds().add("retries", retries);
+ owner.optBinds().add("cachedir", cachedir);
+ owner.optBinds().add("fastestmirror", fastestmirror);
+
+ owner.optBinds().add("excludepkgs", excludepkgs,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(excludepkgs, priority, value);
+ }, nullptr, true
+ );
+ owner.optBinds().add("exclude", excludepkgs, //compatibility with yum
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(excludepkgs, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("includepkgs", includepkgs,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(includepkgs, priority, value);
+ }, nullptr, true
+ );
+ owner.optBinds().add("exclude_from_weak", exclude_from_weak,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(exclude_from_weak, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("exclude_from_weak_autodetect", exclude_from_weak_autodetect);
+
+ owner.optBinds().add("proxy", proxy,
+ [&](Option::Priority priority, const std::string & value){
+ auto tmpValue(value);
+ for (auto & ch : tmpValue)
+ ch = std::tolower(ch);
+ if (tmpValue == "_none_")
+ proxy.set(priority, "");
+ else
+ proxy.set(priority, value);
+ }, nullptr, false
+ );
+
+ owner.optBinds().add("proxy_username", proxy_username);
+ owner.optBinds().add("proxy_password", proxy_password);
+ owner.optBinds().add("proxy_auth_method", proxy_auth_method);
+ owner.optBinds().add("protected_packages", protected_packages,
+ [&](Option::Priority priority, const std::string & value){
+ if (priority >= protected_packages.getPriority())
+ protected_packages.set(priority, resolveGlobs(value));
+ }, nullptr, false
+ );
+
+ owner.optBinds().add("username", username);
+ owner.optBinds().add("password", password);
+ owner.optBinds().add("gpgcheck", gpgcheck);
+ owner.optBinds().add("repo_gpgcheck", repo_gpgcheck);
+ owner.optBinds().add("enabled", enabled);
+ owner.optBinds().add("enablegroups", enablegroups);
+ owner.optBinds().add("bandwidth", bandwidth);
+ owner.optBinds().add("minrate", minrate);
+ owner.optBinds().add("ip_resolve", ip_resolve);
+ owner.optBinds().add("throttle", throttle);
+ owner.optBinds().add("timeout", timeout);
+ owner.optBinds().add("max_parallel_downloads", max_parallel_downloads);
+ owner.optBinds().add("max_downloads_per_mirror", max_downloads_per_mirror);
+ owner.optBinds().add("metadata_expire", metadata_expire);
+ owner.optBinds().add("sslcacert", sslcacert);
+ owner.optBinds().add("sslverify", sslverify);
+ owner.optBinds().add("sslclientcert", sslclientcert);
+ owner.optBinds().add("sslclientkey", sslclientkey);
+ owner.optBinds().add("proxy_sslcacert", proxy_sslcacert);
+ owner.optBinds().add("proxy_sslverify", proxy_sslverify);
+ owner.optBinds().add("proxy_sslclientcert", proxy_sslclientcert);
+ owner.optBinds().add("proxy_sslclientkey", proxy_sslclientkey);
+ owner.optBinds().add("deltarpm", deltarpm);
+ owner.optBinds().add("deltarpm_percentage", deltarpm_percentage);
+ owner.optBinds().add("skip_if_unavailable", skip_if_unavailable);
+ owner.optBinds().add("sslverifystatus", sslverifystatus);
+}
+
+ConfigMain::ConfigMain() { pImpl = std::unique_ptr<Impl>(new Impl(*this)); }
+ConfigMain::~ConfigMain() = default;
+
+OptionNumber<std::int32_t> & ConfigMain::debuglevel() { return pImpl->debuglevel; }
+OptionNumber<std::int32_t> & ConfigMain::errorlevel() { return pImpl->errorlevel; }
+OptionNumber<std::int32_t> & ConfigMain::logfilelevel() { return pImpl->logfilelevel; }
+OptionString & ConfigMain::installroot() { return pImpl->installroot; }
+OptionString & ConfigMain::config_file_path() { return pImpl->config_file_path; }
+OptionBool & ConfigMain::plugins() { return pImpl->plugins; }
+OptionStringList & ConfigMain::pluginpath() { return pImpl->pluginpath; }
+OptionStringList & ConfigMain::pluginconfpath() { return pImpl->pluginconfpath; }
+OptionString & ConfigMain::persistdir() { return pImpl->persistdir; }
+OptionBool & ConfigMain::transformdb() { return pImpl->transformdb; }
+OptionNumber<std::int32_t> & ConfigMain::recent() { return pImpl->recent; }
+OptionBool & ConfigMain::reset_nice() { return pImpl->reset_nice; }
+OptionString & ConfigMain::system_cachedir() { return pImpl->system_cachedir; }
+OptionBool & ConfigMain::cacheonly() { return pImpl->cacheonly; }
+OptionBool & ConfigMain::keepcache() { return pImpl->keepcache; }
+OptionString & ConfigMain::logdir() { return pImpl->logdir; }
+OptionNumber<std::int32_t> & ConfigMain::log_size() { return pImpl->log_size; }
+OptionNumber<std::int32_t> & ConfigMain::log_rotate() { return pImpl->log_rotate; }
+OptionBool & ConfigMain::log_compress() { return pImpl->log_compress; }
+OptionStringList & ConfigMain::varsdir() { return pImpl->varsdir; }
+OptionStringList & ConfigMain::reposdir() { return pImpl->reposdir; }
+OptionBool & ConfigMain::debug_solver() { return pImpl->debug_solver; }
+OptionStringList & ConfigMain::installonlypkgs() { return pImpl->installonlypkgs; }
+OptionStringList & ConfigMain::group_package_types() { return pImpl->group_package_types; }
+OptionStringList & ConfigMain::optional_metadata_types() { return pImpl->optional_metadata_types; }
+OptionNumber<std::uint32_t> & ConfigMain::installonly_limit() { return pImpl->installonly_limit; }
+OptionStringList & ConfigMain::tsflags() { return pImpl->tsflags; }
+OptionBool & ConfigMain::assumeyes() { return pImpl->assumeyes; }
+OptionBool & ConfigMain::assumeno() { return pImpl->assumeno; }
+OptionBool & ConfigMain::check_config_file_age() { return pImpl->check_config_file_age; }
+OptionBool & ConfigMain::defaultyes() { return pImpl->defaultyes; }
+OptionBool & ConfigMain::diskspacecheck() { return pImpl->diskspacecheck; }
+OptionBool & ConfigMain::localpkg_gpgcheck() { return pImpl->localpkg_gpgcheck; }
+OptionBool & ConfigMain::gpgkey_dns_verification() { return pImpl->gpgkey_dns_verification; }
+OptionBool & ConfigMain::obsoletes() { return pImpl->obsoletes; }
+OptionBool & ConfigMain::showdupesfromrepos() { return pImpl->showdupesfromrepos; }
+OptionBool & ConfigMain::exit_on_lock() { return pImpl->exit_on_lock; }
+OptionBool & ConfigMain::allow_vendor_change() { return pImpl->allow_vendor_change; }
+OptionSeconds & ConfigMain::metadata_timer_sync() { return pImpl->metadata_timer_sync; }
+OptionStringList & ConfigMain::disable_excludes() { return pImpl->disable_excludes; }
+OptionEnum<std::string> & ConfigMain::multilib_policy() { return pImpl->multilib_policy; }
+OptionBool & ConfigMain::best() { return pImpl->best; }
+OptionBool & ConfigMain::install_weak_deps() { return pImpl->install_weak_deps; }
+OptionString & ConfigMain::bugtracker_url() { return pImpl->bugtracker_url; }
+OptionBool & ConfigMain::zchunk() { return pImpl->zchunk; }
+OptionEnum<std::string> & ConfigMain::color() { return pImpl->color; }
+OptionString & ConfigMain::color_list_installed_older() { return pImpl->color_list_installed_older; }
+OptionString & ConfigMain::color_list_installed_newer() { return pImpl->color_list_installed_newer; }
+OptionString & ConfigMain::color_list_installed_reinstall() { return pImpl->color_list_installed_reinstall; }
+OptionString & ConfigMain::color_list_installed_extra() { return pImpl->color_list_installed_extra; }
+OptionString & ConfigMain::color_list_available_upgrade() { return pImpl->color_list_available_upgrade; }
+OptionString & ConfigMain::color_list_available_downgrade() { return pImpl->color_list_available_downgrade; }
+OptionString & ConfigMain::color_list_available_reinstall() { return pImpl->color_list_available_reinstall; }
+OptionString & ConfigMain::color_list_available_install() { return pImpl->color_list_available_install; }
+OptionString & ConfigMain::color_update_installed() { return pImpl->color_update_installed; }
+OptionString & ConfigMain::color_update_local() { return pImpl->color_update_local; }
+OptionString & ConfigMain::color_update_remote() { return pImpl->color_update_remote; }
+OptionString & ConfigMain::color_search_match() { return pImpl->color_search_match; }
+OptionBool & ConfigMain::history_record() { return pImpl->history_record; }
+OptionStringList & ConfigMain::history_record_packages() { return pImpl->history_record_packages; }
+OptionString & ConfigMain::rpmverbosity() { return pImpl->rpmverbosity; }
+OptionBool & ConfigMain::strict() { return pImpl->strict; }
+OptionBool & ConfigMain::skip_broken() { return pImpl->skip_broken; }
+OptionBool & ConfigMain::autocheck_running_kernel() { return pImpl->autocheck_running_kernel; }
+OptionBool & ConfigMain::clean_requirements_on_remove() { return pImpl->clean_requirements_on_remove; }
+OptionEnum<std::string> & ConfigMain::history_list_view() { return pImpl->history_list_view; }
+OptionBool & ConfigMain::upgrade_group_objects_upgrade() { return pImpl->upgrade_group_objects_upgrade; }
+OptionPath & ConfigMain::destdir() { return pImpl->destdir; }
+OptionString & ConfigMain::comment() { return pImpl->comment; }
+OptionBool & ConfigMain::downloadonly() { return pImpl->downloadonly; }
+OptionBool & ConfigMain::ignorearch() { return pImpl->ignorearch; }
+
+OptionString & ConfigMain::module_platform_id() { return pImpl->module_platform_id; }
+OptionBool & ConfigMain::module_stream_switch() { return pImpl->module_stream_switch; }
+OptionBool & ConfigMain::module_obsoletes() { return pImpl->module_obsoletes; }
+OptionString & ConfigMain::user_agent() { return pImpl->user_agent; }
+OptionBool & ConfigMain::countme() { return pImpl->countme; }
+OptionBool & ConfigMain::protect_running_kernel() {return pImpl->protect_running_kernel; }
+
+// Repo main config
+OptionNumber<std::uint32_t> & ConfigMain::retries() { return pImpl->retries; }
+OptionString & ConfigMain::cachedir() { return pImpl->cachedir; }
+OptionBool & ConfigMain::fastestmirror() { return pImpl->fastestmirror; }
+OptionStringList & ConfigMain::excludepkgs() { return pImpl->excludepkgs; }
+OptionStringList & ConfigMain::includepkgs() { return pImpl->includepkgs; }
+OptionStringList & ConfigMain::exclude_from_weak() { return pImpl->exclude_from_weak; }
+OptionBool & ConfigMain::exclude_from_weak_autodetect() { return pImpl->exclude_from_weak_autodetect; }
+OptionString & ConfigMain::proxy() { return pImpl->proxy; }
+OptionString & ConfigMain::proxy_username() { return pImpl->proxy_username; }
+OptionString & ConfigMain::proxy_password() { return pImpl->proxy_password; }
+OptionEnum<std::string> & ConfigMain::proxy_auth_method() { return pImpl->proxy_auth_method; }
+OptionStringList & ConfigMain::protected_packages() { return pImpl->protected_packages; }
+OptionString & ConfigMain::username() { return pImpl->username; }
+OptionString & ConfigMain::password() { return pImpl->password; }
+OptionBool & ConfigMain::gpgcheck() { return pImpl->gpgcheck; }
+OptionBool & ConfigMain::repo_gpgcheck() { return pImpl->repo_gpgcheck; }
+OptionBool & ConfigMain::enabled() { return pImpl->enabled; }
+OptionBool & ConfigMain::enablegroups() { return pImpl->enablegroups; }
+OptionNumber<std::uint32_t> & ConfigMain::bandwidth() { return pImpl->bandwidth; }
+OptionNumber<std::uint32_t> & ConfigMain::minrate() { return pImpl->minrate; }
+OptionEnum<std::string> & ConfigMain::ip_resolve() { return pImpl->ip_resolve; }
+OptionNumber<float> & ConfigMain::throttle() { return pImpl->throttle; }
+OptionSeconds & ConfigMain::timeout() { return pImpl->timeout; }
+OptionNumber<std::uint32_t> & ConfigMain::max_parallel_downloads() { return pImpl->max_parallel_downloads; }
+OptionNumber<std::uint32_t> & ConfigMain::max_downloads_per_mirror() { return pImpl->max_downloads_per_mirror; }
+OptionSeconds & ConfigMain::metadata_expire() { return pImpl->metadata_expire; }
+OptionString & ConfigMain::sslcacert() { return pImpl->sslcacert; }
+OptionBool & ConfigMain::sslverify() { return pImpl->sslverify; }
+OptionString & ConfigMain::sslclientcert() { return pImpl->sslclientcert; }
+OptionString & ConfigMain::sslclientkey() { return pImpl->sslclientkey; }
+OptionString & ConfigMain::proxy_sslcacert() { return pImpl->proxy_sslcacert; }
+OptionBool & ConfigMain::proxy_sslverify() { return pImpl->proxy_sslverify; }
+OptionString & ConfigMain::proxy_sslclientcert() { return pImpl->proxy_sslclientcert; }
+OptionString & ConfigMain::proxy_sslclientkey() { return pImpl->proxy_sslclientkey; }
+OptionBool & ConfigMain::deltarpm() { return pImpl->deltarpm; }
+OptionNumber<std::uint32_t> & ConfigMain::deltarpm_percentage() { return pImpl->deltarpm_percentage; }
+OptionBool & ConfigMain::skip_if_unavailable() { return pImpl->skip_if_unavailable; }
+OptionBool & ConfigMain::sslverifystatus() { return pImpl->sslverifystatus; }
+
+static void DIRClose(DIR *d) { closedir(d); }
+
+void ConfigMain::addVarsFromDir(std::map<std::string, std::string> & varsMap, const std::string & dirPath)
+{
+ if (DIR * dir = opendir(dirPath.c_str())) {
+ std::unique_ptr<DIR, decltype(&DIRClose)> dirGuard(dir, &DIRClose);
+ while (auto ent = readdir(dir)) {
+ auto dname = ent->d_name;
+ if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
+ continue;
+
+ auto fullPath = dirPath;
+ if (fullPath.back() != '/')
+ fullPath += "/";
+ fullPath += dname;
+ std::ifstream inStream(fullPath);
+ if (inStream.fail()) {
+ // log.warning()
+ continue;
+ }
+ std::string line;
+ std::getline(inStream, line);
+ if (inStream.fail()) {
+ // log.warning()
+ continue;
+ }
+ varsMap[dname] = std::move(line);
+ }
+ }
+}
+
+void ConfigMain::addVarsFromEnv(std::map<std::string, std::string> & varsMap)
+{
+ if (!environ)
+ return;
+
+ for (const char * const * varPtr = environ; *varPtr; ++varPtr) {
+ auto var = *varPtr;
+ if (auto eqlPtr = strchr(var, '=')) {
+ auto eqlIdx = eqlPtr - var;
+ // DNF[0-9]
+ if (eqlIdx == 4 && strncmp("DNF", var, 3) == 0 && isdigit(var[3]))
+ varsMap[std::string(var, eqlIdx)] = eqlPtr + 1;
+ // DNF_VAR_[A-Za-z0-9_]+ , DNF_VAR_ prefix is cut off
+ else if (eqlIdx > 8 && strncmp("DNF_VAR_", var, 8) == 0 &&
+ static_cast<int>(strspn(var + 8, ASCII_LETTERS DIGITS "_")) == eqlIdx - 8)
+ varsMap[std::string(var + 8, eqlIdx - 8)] = eqlPtr + 1;
+ }
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_MAIN_HPP
+#define _LIBDNF_CONFIG_MAIN_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Config.hpp"
+#include "OptionBool.hpp"
+#include "OptionEnum.hpp"
+#include "OptionNumber.hpp"
+#include "OptionPath.hpp"
+#include "OptionSeconds.hpp"
+#include "OptionString.hpp"
+#include "OptionStringList.hpp"
+
+#include <cstdint>
+#include <memory>
+
+namespace libdnf {
+
+/**
+* @class ConfigMain
+*
+* @brief Holds configuration options needed for libdnf
+*
+*/
+class ConfigMain : public Config {
+public:
+ ConfigMain();
+ ~ConfigMain();
+
+ OptionNumber<std::int32_t> & debuglevel();
+ OptionNumber<std::int32_t> & errorlevel();
+ OptionNumber<std::int32_t> & logfilelevel();
+ OptionString & installroot();
+ OptionString & config_file_path();
+ OptionBool & plugins();
+ OptionStringList & pluginpath();
+ OptionStringList & pluginconfpath();
+ OptionString & persistdir();
+ OptionBool & transformdb();
+ OptionNumber<std::int32_t> & recent();
+ OptionBool & reset_nice();
+ OptionString & system_cachedir();
+ OptionBool & cacheonly();
+ OptionBool & keepcache();
+ OptionString & logdir();
+ OptionNumber<std::int32_t> & log_size();
+ OptionNumber<std::int32_t> & log_rotate();
+ OptionBool & log_compress();
+ OptionStringList & varsdir();
+ OptionStringList & reposdir();
+ OptionBool & debug_solver();
+ OptionStringList & installonlypkgs();
+ OptionStringList & group_package_types();
+ OptionStringList & optional_metadata_types();
+
+ /* NOTE: If you set this to 2, then because it keeps the current
+ kernel it means if you ever install an "old" kernel it'll get rid
+ of the newest one so you probably want to use 3 as a minimum
+ ... if you turn it on. */
+ OptionNumber<std::uint32_t> & installonly_limit();
+
+ OptionStringList & tsflags();
+ OptionBool & assumeyes();
+ OptionBool & assumeno();
+ OptionBool & check_config_file_age();
+ OptionBool & defaultyes();
+ OptionBool & diskspacecheck();
+ OptionBool & localpkg_gpgcheck();
+ OptionBool & gpgkey_dns_verification();
+ OptionBool & obsoletes();
+ OptionBool & showdupesfromrepos();
+ OptionBool & exit_on_lock();
+ OptionBool & allow_vendor_change();
+ OptionSeconds & metadata_timer_sync();
+ OptionStringList & disable_excludes();
+ OptionEnum<std::string> & multilib_policy(); // :api
+ OptionBool & best(); // :api
+ OptionBool & install_weak_deps();
+ OptionString & bugtracker_url();
+ OptionBool & zchunk();
+ OptionEnum<std::string> & color();
+ OptionString & color_list_installed_older();
+ OptionString & color_list_installed_newer();
+ OptionString & color_list_installed_reinstall();
+ OptionString & color_list_installed_extra();
+ OptionString & color_list_available_upgrade();
+ OptionString & color_list_available_downgrade();
+ OptionString & color_list_available_reinstall();
+ OptionString & color_list_available_install();
+ OptionString & color_update_installed();
+ OptionString & color_update_local();
+ OptionString & color_update_remote();
+ OptionString & color_search_match();
+ OptionBool & history_record();
+ OptionStringList & history_record_packages();
+ OptionString & rpmverbosity();
+ OptionBool & strict(); // :api
+ OptionBool & skip_broken(); // :yum-compatibility
+ OptionBool & autocheck_running_kernel(); // :yum-compatibility
+ OptionBool & clean_requirements_on_remove();
+ OptionEnum<std::string> & history_list_view();
+ OptionBool & upgrade_group_objects_upgrade();
+ OptionPath & destdir();
+ OptionString & comment();
+ OptionBool & downloadonly();
+ OptionBool & ignorearch();
+
+ OptionString & module_platform_id();
+ OptionBool & module_stream_switch();
+ OptionBool & module_obsoletes();
+ OptionString & user_agent();
+ OptionBool & countme();
+ OptionBool & protect_running_kernel();
+
+ // Repo main config
+ OptionNumber<std::uint32_t> & retries();
+ OptionString & cachedir();
+ OptionBool & fastestmirror();
+ OptionStringList & excludepkgs();
+ OptionStringList & includepkgs();
+ OptionStringList & exclude_from_weak();
+ OptionBool & exclude_from_weak_autodetect();
+ OptionString & proxy();
+ OptionString & proxy_username();
+ OptionString & proxy_password();
+ OptionEnum<std::string> & proxy_auth_method();
+ OptionStringList & protected_packages();
+ OptionString & username();
+ OptionString & password();
+ OptionBool & gpgcheck();
+ OptionBool & repo_gpgcheck();
+ OptionBool & enabled();
+ OptionBool & enablegroups();
+ OptionNumber<std::uint32_t> & bandwidth();
+ OptionNumber<std::uint32_t> & minrate();
+ OptionEnum<std::string> & ip_resolve();
+ OptionNumber<float> & throttle();
+ OptionSeconds & timeout();
+ OptionNumber<std::uint32_t> & max_parallel_downloads();
+ OptionNumber<std::uint32_t> & max_downloads_per_mirror();
+ OptionSeconds & metadata_expire();
+ OptionString & sslcacert();
+ OptionBool & sslverify();
+ OptionString & sslclientcert();
+ OptionString & sslclientkey();
+ OptionString & proxy_sslcacert();
+ OptionBool & proxy_sslverify();
+ OptionString & proxy_sslclientcert();
+ OptionString & proxy_sslclientkey();
+ OptionBool & deltarpm();
+ OptionNumber<std::uint32_t> & deltarpm_percentage();
+ OptionBool & skip_if_unavailable();
+ OptionBool & sslverifystatus();
+
+ /**
+ * @brief Adds variables from directory
+ *
+ * Additional variables are added from directory. Each file represents one variable.
+ * The variable name is equal to filename and the value is defined by first line of the file.
+ *
+ * @param varsMap Storage where the variables are added.
+ * @param dirPath Path to directory.
+ */
+ static void addVarsFromDir(std::map<std::string, std::string> & varsMap, const std::string & dirPath);
+
+ /**
+ * @brief Adds variables from environment
+ *
+ * Environment variables DNF[0-9] and DNF_VAR_[A-Za-z0-9_]+ are used if exists.
+ * DNF_VAR_ prefix is cut off.
+ *
+ * @param varsMap Storage where the variables are added.
+ */
+ static void addVarsFromEnv(std::map<std::string, std::string> & varsMap);
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ConfigParser.hpp"
+#include "../utils/iniparser/iniparser.hpp"
+
+#include <algorithm>
+#include <fstream>
+
+namespace libdnf {
+
+void ConfigParser::substitute(std::string & text,
+ const std::map<std::string, std::string> & substitutions)
+{
+ text = ConfigParser::substitute_expression(text, substitutions, 0).first;
+}
+
+const unsigned int MAXIMUM_EXPRESSION_DEPTH = 32;
+
+std::pair<std::string, size_t> ConfigParser::substitute_expression(const std::string & text,
+ const std::map<std::string, std::string> & substitutions,
+ unsigned int depth) {
+ if (depth > MAXIMUM_EXPRESSION_DEPTH) {
+ return std::make_pair(std::string(text), text.length());
+ }
+ std::string res{text};
+
+ // The total number of characters read in the replacee
+ size_t total_scanned = 0;
+
+ size_t pos = 0;
+ while (pos < res.length()) {
+ if (res[pos] == '}' && depth > 0) {
+ return std::make_pair(res.substr(0, pos), total_scanned);
+ }
+
+ if (res[pos] == '\\') {
+ // Escape the next character (if there is one)
+ if (pos + 1 >= res.length()) {
+ break;
+ }
+ res.erase(pos, 1);
+ total_scanned += 2;
+ pos += 1;
+ continue;
+ }
+ if (res[pos] == '$') {
+ // variable expression starts after the $ and includes the braces
+ // ${variable:-word}
+ // ^-- pos_variable_expression
+ size_t pos_variable_expression = pos + 1;
+ if (pos_variable_expression >= res.length()) {
+ break;
+ }
+
+ // Does the variable expression use braces? If so, the variable name
+ // starts one character after the start of the variable_expression
+ bool has_braces;
+ size_t pos_variable;
+ if (res[pos_variable_expression] == '{') {
+ has_braces = true;
+ pos_variable = pos_variable_expression + 1;
+ if (pos_variable >= res.length()) {
+ break;
+ }
+ } else {
+ has_braces = false;
+ pos_variable = pos_variable_expression;
+ }
+
+ // Find the end of the variable name
+ auto it = std::find_if_not(res.begin() + static_cast<long>(pos_variable), res.end(), [](char c) {
+ return std::isalnum(c) != 0 || c == '_';
+ });
+ auto pos_after_variable = static_cast<size_t>(std::distance(res.begin(), it));
+
+ // Find the substituting string and the end of the variable expression
+ const auto & variable_key = res.substr(pos_variable, pos_after_variable - pos_variable);
+ const auto variable_mapping = substitutions.find(variable_key);
+
+ // No std::optional here.
+ bool variable_value_has_value{false};
+ std::string variable_value{""};
+
+ if (variable_mapping == substitutions.end()) {
+ if (variable_key == "releasever_major" || variable_key == "releasever_minor") {
+ const auto releasever_mapping = substitutions.find("releasever");
+ if (releasever_mapping != substitutions.end()) {
+ const auto & releasever_split = ConfigParser::split_releasever(releasever_mapping->second);
+ if (variable_key == "releasever_major") {
+ variable_value = std::get<0>(releasever_split);
+ variable_value_has_value = true;
+ } else {
+ variable_value = std::get<1>(releasever_split);
+ variable_value_has_value = true;
+ }
+ }
+ }
+ } else {
+ variable_value = variable_mapping->second;
+ variable_value_has_value = true;
+ }
+
+ // No std::optional here
+ std::string subst_str{""};
+ bool subst_str_has_value{false};
+
+ size_t pos_after_variable_expression;
+
+ if (has_braces) {
+ if (pos_after_variable >= res.length()) {
+ break;
+ }
+ if (res[pos_after_variable] == ':') {
+ if (pos_after_variable + 1 >= res.length()) {
+ break;
+ }
+ char expansion_mode = res[pos_after_variable + 1];
+ size_t pos_word = pos_after_variable + 2;
+ if (pos_word >= res.length()) {
+ break;
+ }
+
+ // Expand the default/alternate expression
+ auto word_str = res.substr(pos_word);
+ auto word_substitution = substitute_expression(word_str, substitutions, depth + 1);
+ auto expanded_word = word_substitution.first;
+ auto scanned = word_substitution.second;
+ auto pos_after_word = pos_word + scanned;
+ if (pos_after_word >= res.length()) {
+ break;
+ }
+ if (res[pos_after_word] != '}') {
+ // The variable expression doesn't end in a '}',
+ // continue after the word and don't expand it
+ total_scanned += pos_after_word - pos;
+ pos = pos_after_word;
+ continue;
+ }
+
+ if (expansion_mode == '-') {
+ // ${variable:-word} (default value)
+ // If variable is unset or empty, the expansion of word is
+ // substituted. Otherwise, the value of variable is
+ // substituted.
+ if (!variable_value_has_value || variable_value.empty()) {
+ subst_str = expanded_word;
+ subst_str_has_value = true;
+ } else {
+ subst_str = variable_value;
+ subst_str_has_value = true;
+ }
+ } else if (expansion_mode == '+') {
+ // ${variable:+word} (alternate value)
+ // If variable is unset or empty nothing is substituted.
+ // Otherwise, the expansion of word is substituted.
+ if (!variable_value_has_value || variable_value.empty()) {
+ subst_str = "";
+ subst_str_has_value = true;
+ } else {
+ subst_str = expanded_word;
+ subst_str_has_value = true;
+ }
+ } else {
+ // Unknown expansion mode, continue after the ':'
+ pos = pos_after_variable + 1;
+ continue;
+ }
+ pos_after_variable_expression = pos_after_word + 1;
+ } else if (res[pos_after_variable] == '}') {
+ // ${variable}
+ if (variable_value_has_value) {
+ subst_str = variable_value;
+ subst_str_has_value = true;
+ }
+ // Move past the closing '}'
+ pos_after_variable_expression = pos_after_variable + 1;
+ } else {
+ // Variable expression doesn't end in a '}', continue after the variable
+ pos = pos_after_variable;
+ continue;
+ }
+ } else {
+ // No braces, we have a $variable
+ if (variable_value_has_value) {
+ subst_str = variable_value;
+ subst_str_has_value = true;
+ }
+ pos_after_variable_expression = pos_after_variable;
+ }
+
+ // If there is no substitution to make, move past the variable expression and continue.
+ if (!subst_str_has_value) {
+ total_scanned += pos_after_variable_expression - pos;
+ pos = pos_after_variable_expression;
+ continue;
+ }
+
+ res.replace(pos, pos_after_variable_expression - pos, subst_str);
+ total_scanned += pos_after_variable_expression - pos;
+ pos += subst_str.length();
+ } else {
+ total_scanned += 1;
+ pos += 1;
+ }
+ }
+
+ // We have reached the end of the text
+ if (depth > 0) {
+ // If we are in a subexpression and we didn't find a closing '}', make no substitutions.
+ return std::make_pair(std::string{text}, text.length());
+ }
+
+ return std::make_pair(res, text.length());
+}
+
+std::tuple<std::string, std::string> ConfigParser::split_releasever(const std::string & releasever)
+{
+ // Uses the same logic as DNF 5 and as splitReleaseverTo in libzypp
+ std::string releasever_major;
+ std::string releasever_minor;
+ const auto pos = releasever.find('.');
+ if (pos == std::string::npos) {
+ releasever_major = releasever;
+ } else {
+ releasever_major = releasever.substr(0, pos);
+ releasever_minor = releasever.substr(pos + 1);
+ }
+ return std::make_tuple(releasever_major, releasever_minor);
+}
+
+static void read(ConfigParser & cfgParser, IniParser & parser)
+{
+ IniParser::ItemType readedType;
+ while ((readedType = parser.next()) != IniParser::ItemType::END_OF_INPUT) {
+ auto section = parser.getSection();
+ if (readedType == IniParser::ItemType::SECTION) {
+ cfgParser.addSection(std::move(section), std::move(parser.getRawItem()));
+ }
+ else if (readedType == IniParser::ItemType::KEY_VAL) {
+ cfgParser.setValue(section, std::move(parser.getKey()), std::move(parser.getValue()), std::move(parser.getRawItem()));
+ }
+ else if (readedType == IniParser::ItemType::COMMENT_LINE || readedType == IniParser::ItemType::EMPTY_LINE) {
+ if (section.empty())
+ cfgParser.getHeader() += parser.getRawItem();
+ else
+ cfgParser.addCommentLine(section, std::move(parser.getRawItem()));
+ }
+ }
+}
+
+void ConfigParser::read(const std::string & filePath)
+{
+ try {
+ IniParser parser(filePath);
+ ::libdnf::read(*this, parser);
+ } catch (const IniParser::CantOpenFile & e) {
+ throw CantOpenFile(e.what());
+ } catch (const IniParser::Exception & e) {
+ throw ParsingError(e.what() + std::string(" at line ") + std::to_string(e.getLineNumber()));
+ }
+}
+
+void ConfigParser::read(std::unique_ptr<std::istream> && inputStream)
+{
+ try {
+ IniParser parser(std::move(inputStream));
+ ::libdnf::read(*this, parser);
+ } catch (const IniParser::CantOpenFile & e) {
+ throw CantOpenFile(e.what());
+ } catch (const IniParser::Exception & e) {
+ throw ParsingError(e.what() + std::string(" at line ") + std::to_string(e.getLineNumber()));
+ }
+}
+
+static std::string createRawItem(const std::string & value, const std::string & oldRawItem)
+{
+ auto eqlPos = oldRawItem.find('=');
+ if (eqlPos == oldRawItem.npos)
+ return "";
+ auto valuepos = oldRawItem.find_first_not_of(" \t", eqlPos + 1);
+ auto keyAndDelimLength = valuepos != oldRawItem.npos ? valuepos : oldRawItem.length();
+ return oldRawItem.substr(0, keyAndDelimLength) + value + '\n';
+}
+
+void ConfigParser::setValue(const std::string & section, const std::string & key, const std::string & value)
+{
+ auto rawIter = rawItems.find(section + ']' + key);
+ auto raw = createRawItem(value, rawIter != rawItems.end() ? rawIter->second : "");
+ setValue(section, key, value, raw);
+}
+
+void ConfigParser::setValue(const std::string & section, std::string && key, std::string && value)
+{
+ auto rawIter = rawItems.find(section + ']' + key);
+ auto raw = createRawItem(value, rawIter != rawItems.end() ? rawIter->second : "");
+ setValue(section, std::move(key), std::move(value), std::move(raw));
+}
+
+const std::string &
+ConfigParser::getValue(const std::string & section, const std::string & key) const
+{
+ auto sect = data.find(section);
+ if (sect == data.end())
+ throw MissingSection("OptionReader::getValue(): Missing section " + section);
+ auto keyVal = sect->second.find(key);
+ if (keyVal == sect->second.end())
+ throw MissingOption("OptionReader::getValue(): Missing option " + key +
+ " in section " + section);
+ return keyVal->second;
+}
+
+std::string
+ConfigParser::getSubstitutedValue(const std::string & section, const std::string & key) const
+{
+ auto ret = getValue(section, key);
+ substitute(ret, substitutions);
+ return ret;
+}
+
+static void writeKeyVals(std::ostream & out, const std::string & section, const ConfigParser::Container::mapped_type & keyValMap, const std::map<std::string, std::string> & rawItems)
+{
+ for (const auto & keyVal : keyValMap) {
+ auto first = keyVal.first[0];
+ if (first == '#' || first == ';')
+ out << keyVal.second;
+ else {
+ auto rawItem = rawItems.find(section + ']' + keyVal.first);
+ if (rawItem != rawItems.end())
+ out << rawItem->second;
+ else {
+ out << keyVal.first << "=";
+ for (const auto chr : keyVal.second) {
+ out << chr;
+ if (chr == '\n')
+ out << " ";
+ }
+ out << "\n";
+ }
+ }
+ }
+}
+
+static void writeSection(std::ostream & out, const std::string & section, const ConfigParser::Container::mapped_type & keyValMap, const std::map<std::string, std::string> & rawItems)
+{
+ auto rawItem = rawItems.find(section);
+ if (rawItem != rawItems.end())
+ out << rawItem->second;
+ else
+ out << "[" << section << "]" << "\n";
+ writeKeyVals(out, section, keyValMap, rawItems);
+}
+
+void ConfigParser::write(const std::string & filePath, bool append) const
+{
+ std::ofstream ofs;
+ ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+ ofs.open(filePath, append ? std::ofstream::app : std::ofstream::trunc);
+ write(ofs);
+}
+
+void ConfigParser::write(const std::string & filePath, bool append, const std::string & section) const
+{
+ auto sit = data.find(section);
+ if (sit == data.end())
+ throw MissingSection("ConfigParser::write(): Missing section " + section);
+ std::ofstream ofs;
+ ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+ ofs.open(filePath, append ? std::ofstream::app : std::ofstream::trunc);
+ writeSection(ofs, sit->first, sit->second, rawItems);
+}
+
+void ConfigParser::write(std::ostream & outputStream) const
+{
+ outputStream << header;
+ for (const auto & section : data) {
+ writeSection(outputStream, section.first, section.second, rawItems);
+ }
+}
+
+void ConfigParser::write(std::ostream & outputStream, const std::string & section) const
+{
+ auto sit = data.find(section);
+ if (sit == data.end())
+ throw MissingSection("ConfigParser::write(): Missing section " + section);
+ writeSection(outputStream, sit->first, sit->second, rawItems);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_CONFIG_PARSER_HPP
+#define LIBDNF_CONFIG_PARSER_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "../utils/PreserveOrderMap.hpp"
+
+#include <istream>
+#include <ostream>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+namespace libdnf {
+
+/**
+* @class ConfigParser
+*
+* @brief Class for parsing dnf/yum .ini configuration files.
+*
+* ConfigParser is used for parsing files. The class adds support for substitutions.
+* User can get both substituded and original parsed values.
+* The parsed items are stored into the PreserveOrderMap.
+* IniParser preserve order of items. Comments and empty lines are kept.
+*/
+struct ConfigParser {
+public:
+ typedef PreserveOrderMap<std::string, PreserveOrderMap<std::string, std::string>> Container;
+
+ struct Exception : public std::runtime_error {
+ Exception(const std::string & what) : runtime_error(what) {}
+ };
+ struct CantOpenFile : public Exception {
+ CantOpenFile(const std::string & what) : Exception(what) {}
+ };
+ struct ParsingError : public Exception {
+ ParsingError(const std::string & what) : Exception(what) {}
+ };
+ struct MissingSection : public Exception {
+ MissingSection(const std::string & what) : Exception(what) {}
+ };
+ struct MissingOption : public Exception {
+ MissingOption(const std::string & what) : Exception(what) {}
+ };
+
+ /**
+ * @brief Substitute values in text according to the substitutions map
+ *
+ * @param text The text for substitution
+ * @param substitutions Substitution map
+ */
+ static void substitute(std::string & text,
+ const std::map<std::string, std::string> & substitutions);
+ void setSubstitutions(const std::map<std::string, std::string> & substitutions);
+ void setSubstitutions(std::map<std::string, std::string> && substitutions);
+ const std::map<std::string, std::string> & getSubstitutions() const;
+ /**
+ * @brief Reads/parse one INI file
+ *
+ * Can be called repeately for reading/merge more INI files.
+ *
+ * @param filePath Name (with path) of file to read
+ */
+ void read(const std::string & filePath);
+ /**
+ * @brief Reads/parse from istream
+ *
+ * Can be called repeately for reading/merge more istreams.
+ *
+ * @param inputStream Stream to read
+ */
+ void read(std::unique_ptr<std::istream> && inputStream);
+ /**
+ * @brief Writes all data (all sections) to INI file
+ *
+ * @param filePath Name (with path) of file to write
+ * @param append If true, existent file will be appended, otherwise overwritten
+ */
+ void write(const std::string & filePath, bool append) const;
+ /**
+ * @brief Writes one section data to INI file
+ *
+ * @param filePath Name (with path) of file to write
+ * @param append If true, existent file will be appended, otherwise overwritten
+ * @param section Section to write
+ */
+ void write(const std::string & filePath, bool append, const std::string & section) const;
+ /**
+ * @brief Writes one section data to stream
+ *
+ * @param outputStream Stream to write
+ * @param section Section to write
+ */
+ void write(std::ostream & outputStream, const std::string & section) const;
+ /**
+ * @brief Writes all data (all sections) to stream
+ *
+ * @param outputStream Stream to write
+ */
+ void write(std::ostream & outputStream) const;
+ bool addSection(const std::string & section, const std::string & rawLine);
+ bool addSection(const std::string & section);
+ bool addSection(std::string && section, std::string && rawLine);
+ bool addSection(std::string && section);
+ bool hasSection(const std::string & section) const noexcept;
+ bool hasOption(const std::string & section, const std::string & key) const noexcept;
+ void setValue(const std::string & section, const std::string & key, const std::string & value, const std::string & rawItem);
+ void setValue(const std::string & section, const std::string & key, const std::string & value);
+ void setValue(const std::string & section, std::string && key, std::string && value, std::string && rawItem);
+ void setValue(const std::string & section, std::string && key, std::string && value);
+ bool removeSection(const std::string & section);
+ bool removeOption(const std::string & section, const std::string & key);
+ void addCommentLine(const std::string & section, const std::string & comment);
+ void addCommentLine(const std::string & section, std::string && comment);
+ const std::string & getValue(const std::string & section, const std::string & key) const;
+ std::string getSubstitutedValue(const std::string & section, const std::string & key) const;
+ const std::string & getHeader() const noexcept;
+ std::string & getHeader() noexcept;
+ const Container & getData() const noexcept;
+ Container & getData() noexcept;
+
+private:
+ std::map<std::string, std::string> substitutions;
+ Container data;
+ int itemNumber{0};
+ std::string header;
+ std::map<std::string, std::string> rawItems;
+
+ /**
+ * @brief Expand variables in a subexpression
+ *
+ * @param text String with variable expressions
+ * @param substitutions Substitution map
+ * @param depth The recursive depth
+ * @return Pair of the resulting string and the number of characters scanned in `text`
+ */
+ static std::pair<std::string, size_t> substitute_expression(const std::string & text,
+ const std::map<std::string, std::string> & substitutions,
+ unsigned int depth);
+
+ static std::tuple<std::string, std::string> split_releasever(const std::string & releasever);
+};
+
+inline void ConfigParser::setSubstitutions(const std::map<std::string, std::string> & substitutions)
+{
+ this->substitutions = substitutions;
+}
+
+inline void ConfigParser::setSubstitutions(std::map<std::string, std::string> && substitutions)
+{
+ this->substitutions = std::move(substitutions);
+}
+
+inline const std::map<std::string, std::string> & ConfigParser::getSubstitutions() const
+{
+ return substitutions;
+}
+
+inline bool ConfigParser::addSection(const std::string & section, const std::string & rawLine)
+{
+ if (data.find(section) != data.end())
+ return false;
+ if (!rawLine.empty())
+ rawItems[section] = rawLine;
+ data[section] = {};
+ return true;
+}
+
+inline bool ConfigParser::addSection(const std::string & section)
+{
+ return addSection(section, "");
+}
+
+inline bool ConfigParser::addSection(std::string && section, std::string && rawLine)
+{
+ if (data.find(section) != data.end())
+ return false;
+ if (!rawLine.empty())
+ rawItems[section] = std::move(rawLine);
+ data[std::move(section)] = {};
+ return true;
+}
+
+inline bool ConfigParser::addSection(std::string && section)
+{
+ return addSection(std::move(section), "");
+}
+
+inline bool ConfigParser::hasSection(const std::string & section) const noexcept
+{
+ return data.find(section) != data.end();
+}
+
+inline bool ConfigParser::hasOption(const std::string & section, const std::string & key) const noexcept
+{
+ auto sectionIter = data.find(section);
+ return sectionIter != data.end() && sectionIter->second.find(key) != sectionIter->second.end();
+}
+
+inline void ConfigParser::setValue(const std::string & section, const std::string & key, const std::string & value, const std::string & rawItem)
+{
+ auto sectionIter = data.find(section);
+ if (sectionIter == data.end())
+ throw MissingSection(section);
+ if (rawItem.empty())
+ rawItems.erase(section + ']' + key);
+ else
+ rawItems[section + ']' + key] = rawItem;
+ sectionIter->second[key] = value;
+}
+
+inline void ConfigParser::setValue(const std::string & section, std::string && key, std::string && value, std::string && rawItem)
+{
+ auto sectionIter = data.find(section);
+ if (sectionIter == data.end())
+ throw MissingSection(section);
+ if (rawItem.empty())
+ rawItems.erase(section + ']' + key);
+ else
+ rawItems[section + ']' + key] = std::move(rawItem);
+ sectionIter->second[std::move(key)] = std::move(value);
+}
+
+inline bool ConfigParser::removeSection(const std::string & section)
+{
+ auto removed = data.erase(section) > 0;
+ if (removed)
+ rawItems.erase(section);
+ return removed;
+}
+
+inline bool ConfigParser::removeOption(const std::string & section, const std::string & key)
+{
+ auto sectionIter = data.find(section);
+ if (sectionIter == data.end())
+ return false;
+ auto removed = sectionIter->second.erase(key) > 0;
+ if (removed)
+ rawItems.erase(section + ']' + key);
+ return removed;
+}
+
+inline void ConfigParser::addCommentLine(const std::string & section, const std::string & comment)
+{
+ auto sectionIter = data.find(section);
+ if (sectionIter == data.end())
+ throw MissingSection(section);
+ sectionIter->second["#"+std::to_string(++itemNumber)] = comment;
+}
+
+inline void ConfigParser::addCommentLine(const std::string & section, std::string && comment)
+{
+ auto sectionIter = data.find(section);
+ if (sectionIter == data.end())
+ throw MissingSection(section);
+ sectionIter->second["#"+std::to_string(++itemNumber)] = std::move(comment);
+}
+
+inline const std::string & ConfigParser::getHeader() const noexcept
+{
+ return header;
+}
+
+inline std::string & ConfigParser::getHeader() noexcept
+{
+ return header;
+}
+
+inline const ConfigParser::Container & ConfigParser::getData() const noexcept
+{
+ return data;
+}
+
+inline ConfigParser::Container & ConfigParser::getData() noexcept
+{
+ return data;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ConfigRepo.hpp"
+#include "Const.hpp"
+#include "Config-private.hpp"
+
+namespace libdnf {
+
+class ConfigRepo::Impl {
+ friend class ConfigRepo;
+
+ Impl(Config & owner, ConfigMain & mainConfig);
+
+ Config & owner;
+ ConfigMain & mainConfig;
+
+ OptionString name{""};
+ OptionChild<OptionBool> enabled{mainConfig.enabled()};
+ OptionChild<OptionString> basecachedir{mainConfig.cachedir()};
+ OptionStringList baseurl{std::vector<std::string>{}};
+ OptionString mirrorlist{nullptr};
+ OptionString metalink{nullptr};
+ OptionString type{""};
+ OptionString mediaid{""};
+ OptionStringList gpgkey{std::vector<std::string>{}};
+ OptionStringList excludepkgs{std::vector<std::string>{}};
+ OptionStringList includepkgs{std::vector<std::string>{}};
+ OptionChild<OptionBool> fastestmirror{mainConfig.fastestmirror()};
+ OptionChild<OptionString> proxy{mainConfig.proxy()};
+ OptionChild<OptionString> proxy_username{mainConfig.proxy_username()};
+ OptionChild<OptionString> proxy_password{mainConfig.proxy_password()};
+ OptionChild<OptionEnum<std::string> > proxy_auth_method{mainConfig.proxy_auth_method()};
+ OptionChild<OptionString> username{mainConfig.username()};
+ OptionChild<OptionString> password{mainConfig.password()};
+ OptionChild<OptionStringList> protected_packages{mainConfig.protected_packages()};
+ OptionChild<OptionBool> gpgcheck{mainConfig.gpgcheck()};
+ OptionChild<OptionBool> repo_gpgcheck{mainConfig.repo_gpgcheck()};
+ OptionChild<OptionBool> enablegroups{mainConfig.enablegroups()};
+ OptionChild<OptionNumber<std::uint32_t> > retries{mainConfig.retries()};
+ OptionChild<OptionNumber<std::uint32_t> > bandwidth{mainConfig.bandwidth()};
+ OptionChild<OptionNumber<std::uint32_t> > minrate{mainConfig.minrate()};
+ OptionChild<OptionEnum<std::string> > ip_resolve{mainConfig.ip_resolve()};
+ OptionChild<OptionNumber<float> > throttle{mainConfig.throttle()};
+ OptionChild<OptionSeconds> timeout{mainConfig.timeout()};
+ OptionChild<OptionNumber<std::uint32_t> > max_parallel_downloads{mainConfig.max_parallel_downloads()};
+ OptionChild<OptionNumber<std::uint32_t> > max_downloads_per_mirror{mainConfig.max_downloads_per_mirror()};
+ OptionChild<OptionSeconds> metadata_expire{mainConfig.metadata_expire()};
+ OptionNumber<std::int32_t> cost{1000};
+ OptionNumber<std::int32_t> priority{99};
+ OptionBool module_hotfixes{false};
+ OptionChild<OptionString> sslcacert{mainConfig.sslcacert()};
+ OptionChild<OptionBool> sslverify{mainConfig.sslverify()};
+ OptionChild<OptionString> sslclientcert{mainConfig.sslclientcert()};
+ OptionChild<OptionString> sslclientkey{mainConfig.sslclientkey()};
+ OptionChild<OptionString> proxy_sslcacert{mainConfig.proxy_sslcacert()};
+ OptionChild<OptionBool> proxy_sslverify{mainConfig.proxy_sslverify()};
+ OptionChild<OptionString> proxy_sslclientcert{mainConfig.proxy_sslclientcert()};
+ OptionChild<OptionString> proxy_sslclientkey{mainConfig.proxy_sslclientkey()};
+ OptionChild<OptionBool> deltarpm{mainConfig.deltarpm()};
+ OptionChild<OptionNumber<std::uint32_t> > deltarpm_percentage{mainConfig.deltarpm_percentage()};
+ OptionChild<OptionBool> skip_if_unavailable{mainConfig.skip_if_unavailable()};
+ OptionString enabled_metadata{""};
+ OptionChild<OptionString> user_agent{mainConfig.user_agent()};
+ OptionChild<OptionBool> countme{mainConfig.countme()};
+ OptionChild<OptionBool> sslverifystatus{mainConfig.sslverifystatus()};
+};
+
+ConfigRepo::Impl::Impl(Config & owner, ConfigMain & mainConfig)
+: owner(owner), mainConfig(mainConfig)
+{
+ owner.optBinds().add("name", name);
+ owner.optBinds().add("enabled", enabled);
+ owner.optBinds().add("cachedir", basecachedir);
+
+ owner.optBinds().add("baseurl", baseurl,
+ [&](Option::Priority priority, const std::string & value) {
+ auto tmpValue = baseurl.fromString(value);
+ for (auto & v : tmpValue) {
+ if (v.substr(0, 1) == "/") {
+ // a local path, turn it into an URL
+ v = "file://" + v;
+ }
+ }
+ baseurl.set(priority, tmpValue);
+ }, nullptr, false
+ );
+
+ owner.optBinds().add("mirrorlist", mirrorlist);
+ owner.optBinds().add("metalink", metalink);
+ owner.optBinds().add("type", type);
+ owner.optBinds().add("mediaid", mediaid);
+ owner.optBinds().add("gpgkey", gpgkey);
+
+ owner.optBinds().add("excludepkgs", excludepkgs,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(excludepkgs, priority, value);
+ }, nullptr, true
+ );
+ owner.optBinds().add("exclude", excludepkgs, //compatibility with yum
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(excludepkgs, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("includepkgs", includepkgs,
+ [&](Option::Priority priority, const std::string & value){
+ optionTListAppend(includepkgs, priority, value);
+ }, nullptr, true
+ );
+
+ owner.optBinds().add("fastestmirror", fastestmirror);
+
+ owner.optBinds().add("proxy", proxy,
+ [&](Option::Priority priority, const std::string & value){
+ auto tmpValue(value);
+ for (auto & ch : tmpValue)
+ ch = std::tolower(ch);
+ if (tmpValue == "_none_")
+ proxy.set(priority, "");
+ else
+ proxy.set(priority, value);
+ }, nullptr, false
+ );
+
+ owner.optBinds().add("proxy_username", proxy_username);
+ owner.optBinds().add("proxy_password", proxy_password);
+ owner.optBinds().add("proxy_auth_method", proxy_auth_method);
+ owner.optBinds().add("username", username);
+ owner.optBinds().add("password", password);
+ owner.optBinds().add("protected_packages", protected_packages);
+ owner.optBinds().add("gpgcheck", gpgcheck);
+ owner.optBinds().add("repo_gpgcheck", repo_gpgcheck);
+ owner.optBinds().add("enablegroups", enablegroups);
+ owner.optBinds().add("retries", retries);
+ owner.optBinds().add("bandwidth", bandwidth);
+ owner.optBinds().add("minrate", minrate);
+ owner.optBinds().add("ip_resolve", ip_resolve);
+ owner.optBinds().add("throttle", throttle);
+ owner.optBinds().add("timeout", timeout);
+ owner.optBinds().add("max_parallel_downloads", max_parallel_downloads);
+ owner.optBinds().add("max_downloads_per_mirror", max_downloads_per_mirror);
+ owner.optBinds().add("metadata_expire", metadata_expire);
+ owner.optBinds().add("cost", cost);
+ owner.optBinds().add("priority", priority);
+ owner.optBinds().add("module_hotfixes", module_hotfixes);
+ owner.optBinds().add("sslcacert", sslcacert);
+ owner.optBinds().add("sslverify", sslverify);
+ owner.optBinds().add("sslclientcert", sslclientcert);
+ owner.optBinds().add("sslclientkey", sslclientkey);
+ owner.optBinds().add("proxy_sslcacert", proxy_sslcacert);
+ owner.optBinds().add("proxy_sslverify", proxy_sslverify);
+ owner.optBinds().add("proxy_sslclientcert", proxy_sslclientcert);
+ owner.optBinds().add("proxy_sslclientkey", proxy_sslclientkey);
+ owner.optBinds().add("deltarpm", deltarpm);
+ owner.optBinds().add("deltarpm_percentage", deltarpm_percentage);
+ owner.optBinds().add("skip_if_unavailable", skip_if_unavailable);
+ owner.optBinds().add("enabled_metadata", enabled_metadata);
+ owner.optBinds().add("user_agent", user_agent);
+ owner.optBinds().add("countme", countme);
+ owner.optBinds().add("sslverifystatus", sslverifystatus);
+}
+
+ConfigRepo::ConfigRepo(ConfigMain & mainConfig) : pImpl(new Impl(*this, mainConfig)) {}
+ConfigRepo::~ConfigRepo() = default;
+ConfigRepo::ConfigRepo(ConfigRepo && src) : pImpl(std::move(src.pImpl)) {}
+
+ConfigMain & ConfigRepo::getMainConfig() { return pImpl->mainConfig; }
+
+OptionString & ConfigRepo::name() { return pImpl->name; }
+OptionChild<OptionBool> & ConfigRepo::enabled() { return pImpl->enabled; }
+OptionChild<OptionString> & ConfigRepo::basecachedir() { return pImpl->basecachedir; }
+OptionStringList & ConfigRepo::baseurl() { return pImpl->baseurl; }
+OptionString & ConfigRepo::mirrorlist() { return pImpl->mirrorlist; }
+OptionString & ConfigRepo::metalink() { return pImpl->metalink; }
+OptionString & ConfigRepo::type() { return pImpl->type; }
+OptionString & ConfigRepo::mediaid() { return pImpl->mediaid; }
+OptionStringList & ConfigRepo::gpgkey() { return pImpl->gpgkey; }
+OptionStringList & ConfigRepo::excludepkgs() { return pImpl->excludepkgs; }
+OptionStringList & ConfigRepo::includepkgs() { return pImpl->includepkgs; }
+OptionChild<OptionBool> & ConfigRepo::fastestmirror() { return pImpl->fastestmirror; }
+OptionChild<OptionString> & ConfigRepo::proxy() { return pImpl->proxy; }
+OptionChild<OptionString> & ConfigRepo::proxy_username() { return pImpl->proxy_username; }
+OptionChild<OptionString> & ConfigRepo::proxy_password() { return pImpl->proxy_password; }
+OptionChild<OptionEnum<std::string> > & ConfigRepo::proxy_auth_method() { return pImpl->proxy_auth_method; }
+OptionChild<OptionString> & ConfigRepo::username() { return pImpl->username; }
+OptionChild<OptionString> & ConfigRepo::password() { return pImpl->password; }
+OptionChild<OptionStringList> & ConfigRepo::protected_packages() { return pImpl->protected_packages; }
+OptionChild<OptionBool> & ConfigRepo::gpgcheck() { return pImpl->gpgcheck; }
+OptionChild<OptionBool> & ConfigRepo::repo_gpgcheck() { return pImpl->repo_gpgcheck; }
+OptionChild<OptionBool> & ConfigRepo::enablegroups() { return pImpl->enablegroups; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::retries() { return pImpl->retries; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::bandwidth() { return pImpl->bandwidth; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::minrate() { return pImpl->minrate; }
+OptionChild<OptionEnum<std::string> > & ConfigRepo::ip_resolve() { return pImpl->ip_resolve; }
+OptionChild<OptionNumber<float> > & ConfigRepo::throttle() { return pImpl->throttle; }
+OptionChild<OptionSeconds> & ConfigRepo::timeout() { return pImpl->timeout; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::max_parallel_downloads() { return pImpl->max_parallel_downloads; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::max_downloads_per_mirror() { return pImpl->max_downloads_per_mirror; }
+OptionChild<OptionSeconds> & ConfigRepo::metadata_expire() { return pImpl->metadata_expire; }
+OptionNumber<std::int32_t> & ConfigRepo::cost() { return pImpl->cost; }
+OptionNumber<std::int32_t> & ConfigRepo::priority() { return pImpl->priority; }
+OptionBool & ConfigRepo::module_hotfixes() { return pImpl->module_hotfixes; }
+OptionChild<OptionString> & ConfigRepo::sslcacert() { return pImpl->sslcacert; }
+OptionChild<OptionBool> & ConfigRepo::sslverify() { return pImpl->sslverify; }
+OptionChild<OptionString> & ConfigRepo::sslclientcert() { return pImpl->sslclientcert; }
+OptionChild<OptionString> & ConfigRepo::sslclientkey() { return pImpl->sslclientkey; }
+OptionChild<OptionString> & ConfigRepo::proxy_sslcacert() { return pImpl->proxy_sslcacert; }
+OptionChild<OptionBool> & ConfigRepo::proxy_sslverify() { return pImpl->proxy_sslverify; }
+OptionChild<OptionString> & ConfigRepo::proxy_sslclientcert() { return pImpl->proxy_sslclientcert; }
+OptionChild<OptionString> & ConfigRepo::proxy_sslclientkey() { return pImpl->proxy_sslclientkey; }
+OptionChild<OptionBool> & ConfigRepo::deltarpm() { return pImpl->deltarpm; }
+OptionChild<OptionNumber<std::uint32_t> > & ConfigRepo::deltarpm_percentage() { return pImpl->deltarpm_percentage; }
+OptionChild<OptionBool> & ConfigRepo::skip_if_unavailable() { return pImpl->skip_if_unavailable; }
+OptionString & ConfigRepo::enabled_metadata() { return pImpl->enabled_metadata; }
+OptionChild<OptionString> & ConfigRepo::user_agent() { return pImpl->user_agent; }
+OptionChild<OptionBool> & ConfigRepo::countme() { return pImpl->countme; }
+OptionChild<OptionBool> & ConfigRepo::sslverifystatus() { return pImpl->sslverifystatus; }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_REPO_HPP
+#define _LIBDNF_CONFIG_REPO_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "ConfigMain.hpp"
+#include "OptionChild.hpp"
+
+#include <cstdint>
+#include <memory>
+
+namespace libdnf {
+
+/**
+* @class ConfigRepo
+*
+* @brief Holds repo configuration options
+*
+* Default values of some options are inherited from ConfigMain.
+*
+*/
+class ConfigRepo : public Config {
+public:
+ ConfigRepo(ConfigMain & mainConfig);
+ ~ConfigRepo();
+ ConfigRepo(ConfigRepo && src);
+
+ ConfigMain & getMainConfig();
+
+ OptionString & name();
+ OptionChild<OptionBool> & enabled();
+ OptionChild<OptionString> & basecachedir();
+ OptionStringList & baseurl();
+ OptionString & mirrorlist();
+ OptionString & metalink();
+ OptionString & type();
+ OptionString & mediaid();
+ OptionStringList & gpgkey();
+ OptionStringList & excludepkgs();
+ OptionStringList & includepkgs();
+ OptionChild<OptionBool> & fastestmirror();
+ OptionChild<OptionString> & proxy();
+ OptionChild<OptionString> & proxy_username();
+ OptionChild<OptionString> & proxy_password();
+ OptionChild<OptionEnum<std::string> > & proxy_auth_method();
+ OptionChild<OptionString> & username();
+ OptionChild<OptionString> & password();
+ OptionChild<OptionStringList> & protected_packages();
+ OptionChild<OptionBool> & gpgcheck();
+ OptionChild<OptionBool> & repo_gpgcheck();
+ OptionChild<OptionBool> & enablegroups();
+ OptionChild<OptionNumber<std::uint32_t> > & retries();
+ OptionChild<OptionNumber<std::uint32_t> > & bandwidth();
+ OptionChild<OptionNumber<std::uint32_t> > & minrate();
+ OptionChild<OptionEnum<std::string> > & ip_resolve();
+ OptionChild<OptionNumber<float> > & throttle();
+ OptionChild<OptionSeconds> & timeout();
+ OptionChild<OptionNumber<std::uint32_t> > & max_parallel_downloads();
+ OptionChild<OptionNumber<std::uint32_t> > & max_downloads_per_mirror();
+ OptionChild<OptionSeconds> & metadata_expire();
+ OptionNumber<std::int32_t> & cost();
+ OptionNumber<std::int32_t> & priority();
+ OptionBool & module_hotfixes();
+ OptionChild<OptionString> & sslcacert();
+ OptionChild<OptionBool> & sslverify();
+ OptionChild<OptionString> & sslclientcert();
+ OptionChild<OptionString> & sslclientkey();
+ OptionChild<OptionString> & proxy_sslcacert();
+ OptionChild<OptionBool> & proxy_sslverify();
+ OptionChild<OptionString> & proxy_sslclientcert();
+ OptionChild<OptionString> & proxy_sslclientkey();
+ OptionChild<OptionBool> & deltarpm();
+ OptionChild<OptionNumber<std::uint32_t> > & deltarpm_percentage();
+ OptionChild<OptionBool> & skip_if_unavailable();
+ // option recognized by other tools, e.g. gnome-software, but unused in dnf
+ OptionString & enabled_metadata();
+ OptionChild<OptionString> & user_agent();
+ OptionChild<OptionBool> & countme();
+ // yum compatibility options
+ OptionChild<OptionBool> & sslverifystatus();
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_CONST_HPP
+#define _LIBDNF_CONFIG_CONST_HPP
+
+#include <string>
+#include <vector>
+
+namespace libdnf {
+
+constexpr const char * PERSISTDIR = "/var/lib/dnf";
+constexpr const char * SYSTEM_CACHEDIR = "/var/cache/dnf";
+
+constexpr const char * CONF_FILENAME = "/etc/dnf/dnf.conf";
+
+// More important varsdirs must be on the end of vector
+const std::vector<std::string> VARS_DIRS{"/etc/yum/vars", "/etc/dnf/vars"};
+
+const std::vector<std::string> GROUP_PACKAGE_TYPES{"mandatory", "default", "conditional"};
+const std::vector<std::string> INSTALLONLYPKGS{"kernel", "kernel-PAE",
+ "installonlypkg(kernel)",
+ "installonlypkg(kernel-module)",
+ "installonlypkg(vm)",
+ "multiversion(kernel)"};
+
+constexpr const char * BUGTRACKER="https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=dnf";
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_HPP
+#define _LIBDNF_OPTION_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include <stdexcept>
+#include <string>
+
+namespace libdnf {
+
+class Option {
+public:
+ enum class Priority {
+ EMPTY = 0,
+ DEFAULT = 10,
+ MAINCONFIG = 20,
+ AUTOMATICCONFIG = 30,
+ REPOCONFIG = 40,
+ PLUGINDEFAULT = 50,
+ PLUGINCONFIG = 60,
+ DROPINCONFIG = 65,
+ COMMANDLINE = 70,
+ RUNTIME = 80
+ };
+
+ struct Exception : public std::runtime_error {
+ Exception(const std::string & msg) : runtime_error(msg) {}
+ Exception(const char * msg) : runtime_error(msg) {}
+ };
+ struct InvalidValue : Exception {
+ InvalidValue(const std::string & msg) : Exception(msg) {}
+ InvalidValue(const char * msg) : Exception(msg) {}
+ };
+ struct ValueNotSet : Exception {
+ ValueNotSet(const std::string & msg) : Exception(msg) {}
+ ValueNotSet(const char * msg) : Exception(msg) {}
+ };
+
+ Option(Priority priority = Priority::EMPTY);
+ virtual Option * clone() const = 0;
+ virtual Priority getPriority() const;
+ virtual void set(Priority priority, const std::string & value) = 0;
+ virtual std::string getValueString() const = 0;
+ virtual bool empty() const noexcept;
+ /// Resets the option to its initial state.
+ virtual void reset() = 0;
+ virtual ~Option() = default;
+
+protected:
+ Priority priority;
+};
+
+inline Option::Option(Priority priority)
+: priority(priority) {}
+
+inline Option::Priority Option::getPriority() const
+{
+ return priority;
+}
+
+inline bool Option::empty() const noexcept
+{
+ return priority == Priority::EMPTY;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionBinds.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+#include <utility>
+
+namespace libdnf {
+
+// ========== OptionBinds::Item class ===============
+
+OptionBinds::Item::Item(Option & option, const NewStringFunc & newString,
+ const GetValueStringFunc & getValueString, bool addValue)
+: option(&option), newStr(newString), getValueStr(getValueString), addValue(addValue) {}
+
+OptionBinds::Item::Item(Option & option, NewStringFunc && newString,
+ GetValueStringFunc && getValueString, bool addValue)
+: option(&option), newStr(std::move(newString)), getValueStr(std::move(getValueString)), addValue(addValue) {}
+
+OptionBinds::Item::Item(Option & option)
+: option(&option) {}
+
+Option::Priority OptionBinds::Item::getPriority() const
+{
+ return option->getPriority();
+}
+
+void OptionBinds::Item::newString(Option::Priority priority, const std::string & value)
+{
+ if (newStr)
+ newStr(priority, value);
+ else
+ option->set(priority, value);
+}
+
+std::string OptionBinds::Item::getValueString() const
+{
+ if (getValueStr)
+ return getValueStr();
+ else
+ return option->getValueString();
+}
+
+bool OptionBinds::Item::getAddValue() const
+{
+ return addValue;
+}
+
+const Option & OptionBinds::Item::getOption() const
+{
+ return *option;
+}
+
+Option & OptionBinds::Item::getOption()
+{
+ return *option;
+}
+
+// =========== OptionBinds class ===============
+
+const char * OptionBinds::OutOfRange::what() const noexcept
+{
+ try {
+ if (tmpMsg.empty())
+ tmpMsg = tfm::format(_("Configuration: OptionBinding with id \"%s\" does not exist"),
+ Exception::what());
+ return tmpMsg.c_str();
+ } catch (...) {
+ return Exception::what();
+ }
+}
+
+const char * OptionBinds::AlreadyExists::what() const noexcept
+{
+ try {
+ if (tmpMsg.empty())
+ tmpMsg = tfm::format(_("Configuration: OptionBinding with id \"%s\" already exists"),
+ Exception::what());
+ return tmpMsg.c_str();
+ } catch (...) {
+ return Exception::what();
+ }
+}
+
+OptionBinds::Item & OptionBinds::at(const std::string & id)
+{
+ auto item = items.find(id);
+ if (item == items.end())
+ throw OutOfRange(id);
+ return item->second;
+}
+
+const OptionBinds::Item & OptionBinds::at(const std::string & id) const
+{
+ auto item = items.find(id);
+ if (item == items.end())
+ throw OutOfRange(id);
+ return item->second;
+}
+
+OptionBinds::Item & OptionBinds::add(const std::string & id, Option & option,
+ const Item::NewStringFunc & newString, const Item::GetValueStringFunc & getValueString, bool addValue)
+{
+ auto item = items.find(id);
+ if (item != items.end())
+ throw AlreadyExists(id);
+ auto res = items.emplace(id, Item(option, newString, getValueString, addValue));
+ return res.first->second;
+}
+
+OptionBinds::Item & OptionBinds::add(const std::string & id, Option & option,
+ Item::NewStringFunc && newString, Item::GetValueStringFunc && getValueString, bool addValue)
+{
+ auto item = items.find(id);
+ if (item != items.end())
+ throw AlreadyExists(id);
+ auto res = items.emplace(id, Item(option, std::move(newString), std::move(getValueString), addValue));
+ return res.first->second;
+}
+
+OptionBinds::Item & OptionBinds::add(const std::string & id, Option & option)
+{
+ auto item = items.find(id);
+ if (item != items.end())
+ throw AlreadyExists(id);
+ auto res = items.emplace(id, Item(option));
+ return res.first->second;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_BINDS_HPP
+#define _LIBDNF_OPTION_BINDS_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+#include <functional>
+#include <map>
+
+namespace libdnf {
+
+class OptionBinds {
+public:
+ struct Exception : public std::runtime_error {
+ Exception(const std::string & what) : runtime_error(what) {}
+ protected:
+ mutable std::string tmpMsg;
+ };
+ struct OutOfRange : public Exception {
+ OutOfRange(const std::string & id) : Exception(id) {}
+ const char * what() const noexcept override;
+ };
+ struct AlreadyExists : public Exception {
+ AlreadyExists(const std::string & id) : Exception(id) {}
+ const char * what() const noexcept override;
+ };
+
+ class Item final {
+ public:
+ typedef std::function<void(Option::Priority, const std::string &)> NewStringFunc;
+ typedef std::function<const std::string & ()> GetValueStringFunc;
+
+ Option::Priority getPriority() const;
+ void newString(Option::Priority priority, const std::string & value);
+ std::string getValueString() const;
+ bool getAddValue() const;
+ const Option & getOption() const;
+ Option & getOption();
+
+ private:
+ friend class OptionBinds;
+
+ Item(Option & option, const NewStringFunc & newString,
+ const GetValueStringFunc & getValueString, bool addValue);
+ Item(Option & option, NewStringFunc && newString,
+ GetValueStringFunc && getValueString, bool addValue);
+ Item(Option & option);
+ Option * option;
+ NewStringFunc newStr;
+ GetValueStringFunc getValueStr;
+ bool addValue{false}; // hint that new value be added
+ };
+
+ typedef std::map<std::string, Item> Container;
+ typedef Container::iterator iterator;
+ typedef Container::const_iterator const_iterator;
+
+ Item & add(const std::string & id, Option & option, const Item::NewStringFunc & newString,
+ const Item::GetValueStringFunc & getValueString, bool addValue);
+ Item & add(const std::string & id, Option & option, Item::NewStringFunc && newString,
+ Item::GetValueStringFunc && getValueString, bool addValue);
+ Item & add(const std::string & id, Option & option);
+ Item & at(const std::string & id);
+ const Item & at(const std::string & id) const;
+ bool empty() const noexcept { return items.empty(); }
+ std::size_t size() const noexcept { return items.size(); }
+ iterator begin() noexcept { return items.begin(); }
+ const_iterator begin() const noexcept { return items.begin(); }
+ const_iterator cbegin() const noexcept { return items.cbegin(); }
+ iterator end() noexcept { return items.end(); }
+ const_iterator end() const noexcept { return items.end(); }
+ const_iterator cend() const noexcept { return items.cend(); }
+ iterator find(const std::string & id) { return items.find(id); }
+ const_iterator find(const std::string & id) const { return items.find(id); }
+
+private:
+ Container items;
+};
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionBool.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+namespace libdnf {
+
+OptionBool::OptionBool(bool defaultValue, const char * const trueVals[], const char * const falseVals[])
+: Option(Priority::DEFAULT), trueValues(trueVals), falseValues(falseVals)
+, defaultValue(defaultValue), value(defaultValue) {}
+
+OptionBool::OptionBool(bool defaultValue)
+: OptionBool(defaultValue, nullptr, nullptr) {}
+
+bool OptionBool::fromString(std::string value) const
+{
+ for (auto & ch : value)
+ ch = std::tolower(ch);
+ for (auto it = getFalseValues(); *it; ++it) {
+ if (value == *it)
+ return false;
+ }
+ for (auto it = getTrueValues(); *it; ++it) {
+ if (value == *it)
+ return true;
+ }
+ throw InvalidValue(tfm::format(_("invalid boolean value '%s'"), value));
+}
+
+void OptionBool::set(Priority priority, bool value)
+{
+ if (priority >= this->priority) {
+ this->value = value;
+ this->priority = priority;
+ }
+}
+
+void OptionBool::set(Priority priority, const std::string & value)
+{
+ set(priority, fromString(value));
+}
+
+std::string OptionBool::toString(bool value) const
+{
+ std::ostringstream oss;
+ oss << value;
+ return oss.str();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_BOOL_HPP
+#define _LIBDNF_OPTION_BOOL_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+namespace libdnf {
+
+constexpr const char * defTrueValues[]{"1", "yes", "true", "on", nullptr};
+constexpr const char * defFalseValues[]{"0", "no", "false", "off", nullptr};
+
+class OptionBool : public Option {
+public:
+ typedef bool ValueType;
+
+ OptionBool(bool defaultValue, const char * const trueVals[], const char * const falseVals[]);
+ OptionBool(bool defaultValue);
+ OptionBool * clone() const override;
+ void test(bool) const;
+ bool fromString(std::string value) const;
+ void set(Priority priority, bool value);
+ void set(Priority priority, const std::string & value) override;
+ bool getValue() const noexcept;
+ bool getDefaultValue() const noexcept;
+ std::string toString(bool value) const;
+ std::string getValueString() const override;
+ const char * const * getTrueValues() const noexcept;
+ const char * const * getFalseValues() const noexcept;
+ void reset() override;
+
+protected:
+ const char * const * const trueValues;
+ const char * const * const falseValues;
+ bool defaultValue;
+ bool value;
+};
+
+inline OptionBool * OptionBool::clone() const
+{
+ return new OptionBool(*this);
+}
+
+inline void OptionBool::test(bool) const {}
+
+inline bool OptionBool::getValue() const noexcept
+{
+ return value;
+}
+
+inline bool OptionBool::getDefaultValue() const noexcept
+{
+ return defaultValue;
+}
+
+inline std::string OptionBool::getValueString() const
+{
+ return toString(value);
+}
+
+inline const char * const * OptionBool::getTrueValues() const noexcept
+{
+ return trueValues ? trueValues : defTrueValues;
+}
+
+inline const char * const * OptionBool::getFalseValues() const noexcept
+{
+ return falseValues ? falseValues : defFalseValues;
+}
+
+inline void OptionBool::reset()
+{
+ value = defaultValue;
+ priority = Priority::DEFAULT;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_CHILD_HPP
+#define _LIBDNF_OPTION_CHILD_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+namespace libdnf {
+
+template <class ParentOptionType, class Enable = void>
+class OptionChild : public Option {
+public:
+ OptionChild(const ParentOptionType & parent);
+ OptionChild * clone() const override;
+ Priority getPriority() const override;
+ void set(Priority priority, const typename ParentOptionType::ValueType & value);
+ void set(Priority priority, const std::string & value) override;
+ const typename ParentOptionType::ValueType getValue() const;
+ const typename ParentOptionType::ValueType getDefaultValue() const;
+ std::string getValueString() const override;
+ bool empty() const noexcept override;
+ void reset() override;
+
+private:
+ const ParentOptionType * parent;
+ typename ParentOptionType::ValueType value;
+};
+
+template <class ParentOptionType>
+class OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type> : public Option {
+public:
+ OptionChild(const ParentOptionType & parent);
+ OptionChild * clone() const override;
+ Priority getPriority() const override;
+ void set(Priority priority, const std::string & value) override;
+ const std::string & getValue() const;
+ const std::string & getDefaultValue() const;
+ std::string getValueString() const override;
+ bool empty() const noexcept override;
+ void reset() override;
+
+private:
+ const ParentOptionType * parent;
+ std::string value;
+};
+
+template <class ParentOptionType, class Enable>
+inline OptionChild<ParentOptionType, Enable>::OptionChild(const ParentOptionType & parent)
+: parent(&parent) {}
+
+template <class ParentOptionType, class Enable>
+inline OptionChild<ParentOptionType, Enable> * OptionChild<ParentOptionType, Enable>::clone() const
+{
+ return new OptionChild<ParentOptionType>(*this);
+}
+
+template <class ParentOptionType, class Enable>
+inline Option::Priority OptionChild<ParentOptionType, Enable>::getPriority() const
+{
+ return priority != Priority::EMPTY ? priority : parent->getPriority();
+}
+
+template <class ParentOptionType, class Enable>
+inline void OptionChild<ParentOptionType, Enable>::set(Priority priority, const typename ParentOptionType::ValueType & value)
+{
+ if (priority >= this->priority) {
+ parent->test(value);
+ this->priority = priority;
+ this->value = value;
+ }
+}
+
+template <class ParentOptionType, class Enable>
+inline void OptionChild<ParentOptionType, Enable>::set(Priority priority, const std::string & value)
+{
+ if (priority >= this->priority)
+ set(priority, parent->fromString(value));
+}
+
+template <class ParentOptionType, class Enable>
+inline const typename ParentOptionType::ValueType OptionChild<ParentOptionType, Enable>::getValue() const
+{
+ return priority != Priority::EMPTY ? value : parent->getValue();
+}
+
+template <class ParentOptionType, class Enable>
+inline const typename ParentOptionType::ValueType OptionChild<ParentOptionType, Enable>::getDefaultValue() const
+{
+ return parent->getDefaultValue();
+}
+
+template <class ParentOptionType, class Enable>
+inline std::string OptionChild<ParentOptionType, Enable>::getValueString() const
+{
+ return priority != Priority::EMPTY ? parent->toString(value) : parent->getValueString();
+}
+
+template <class ParentOptionType, class Enable>
+inline bool OptionChild<ParentOptionType, Enable>::empty() const noexcept
+{
+ return priority == Priority::EMPTY && parent->empty();
+}
+
+template <class ParentOptionType, class Enable>
+inline void OptionChild<ParentOptionType, Enable>::reset()
+{
+ priority = Priority::EMPTY;
+}
+
+template <class ParentOptionType>
+inline OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::OptionChild(const ParentOptionType & parent)
+: parent(&parent) {}
+
+template <class ParentOptionType>
+inline OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type> *
+OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::clone() const
+{
+ return new OptionChild<ParentOptionType>(*this);
+}
+
+template <class ParentOptionType>
+inline Option::Priority OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::getPriority() const
+{
+ return priority != Priority::EMPTY ? priority : parent->getPriority();
+}
+
+template <class ParentOptionType>
+inline void OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::set(Priority priority, const std::string & value)
+{
+ auto val = parent->fromString(value);
+ if (priority >= this->priority) {
+ parent->test(val);
+ this->priority = priority;
+ this->value = val;
+ }
+}
+
+template <class ParentOptionType>
+inline const std::string & OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::getValue() const
+{
+ return priority != Priority::EMPTY ? value : parent->getValue();
+}
+
+template <class ParentOptionType>
+inline const std::string & OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::getDefaultValue() const
+{
+ return parent->getDefaultValue();
+}
+
+template <class ParentOptionType>
+inline std::string OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::getValueString() const
+{
+ return priority != Priority::EMPTY ? value : parent->getValue();
+}
+
+template <class ParentOptionType>
+inline bool OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::empty() const noexcept
+{
+ return priority == Priority::EMPTY && parent->empty();
+}
+
+template <class ParentOptionType>
+inline void OptionChild<ParentOptionType, typename std::enable_if<std::is_same<typename ParentOptionType::ValueType, std::string>::value>::type>::reset()
+{
+ priority = Priority::EMPTY;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionEnum.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+#include <sstream>
+
+namespace libdnf {
+
+template <typename T>
+bool fromString(T & out, const std::string & in, std::ios_base & (*manipulator)(std::ios_base &))
+{
+ std::istringstream iss(in);
+ return !(iss >> manipulator >> out).fail();
+}
+
+template <typename T>
+OptionEnum<T>::OptionEnum(ValueType defaultValue, const std::vector<ValueType> & enumVals)
+: Option(Priority::DEFAULT), enumVals(enumVals), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+OptionEnum<T>::OptionEnum(ValueType defaultValue, std::vector<ValueType> && enumVals)
+: Option(Priority::DEFAULT), enumVals(std::move(enumVals)), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+OptionEnum<T>::OptionEnum(ValueType defaultValue, const std::vector<ValueType> & enumVals, FromStringFunc && fromStringFunc)
+: Option(Priority::DEFAULT), fromStringUser(std::move(fromStringFunc))
+, enumVals(enumVals), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+OptionEnum<T>::OptionEnum(ValueType defaultValue, std::vector<ValueType> && enumVals, FromStringFunc && fromStringFunc)
+: Option(Priority::DEFAULT), fromStringUser(std::move(fromStringFunc))
+, enumVals(std::move(enumVals)), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+void OptionEnum<T>::test(ValueType value) const
+{
+ auto it = std::find(enumVals.begin(), enumVals.end(), value);
+ if (it == enumVals.end())
+ throw InvalidValue(tfm::format(_("'%s' is not an allowed value"), value));
+}
+
+template <typename T>
+T OptionEnum<T>::fromString(const std::string & value) const
+{
+ if (fromStringUser)
+ return fromStringUser(value);
+ T val;
+ if (libdnf::fromString<ValueType>(val, value, std::dec))
+ return val;
+ throw InvalidValue(_("invalid value"));
+}
+
+template <typename T>
+void OptionEnum<T>::set(Priority priority, ValueType value)
+{
+ if (priority >= this->priority) {
+ test(value);
+ this->value = value;
+ this->priority = priority;
+ }
+}
+
+template <typename T>
+void OptionEnum<T>::set(Priority priority, const std::string & value)
+{
+ set(priority, fromString(value));
+}
+
+template <typename T>
+T OptionEnum<T>::getValue() const
+{
+ return value;
+}
+
+template <typename T>
+T OptionEnum<T>::getDefaultValue() const
+{
+ return defaultValue;
+}
+
+template <typename T>
+std::string OptionEnum<T>::toString(ValueType value) const
+{
+ std::ostringstream oss;
+ oss << value;
+ return oss.str();
+}
+
+template <typename T>
+std::string OptionEnum<T>::getValueString() const
+{
+ return toString(value);
+}
+
+OptionEnum<std::string>::OptionEnum(const std::string & defaultValue, const std::vector<ValueType> & enumVals)
+: Option(Priority::DEFAULT), enumVals(enumVals), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+OptionEnum<std::string>::OptionEnum(const std::string & defaultValue, std::vector<ValueType> && enumVals)
+: Option(Priority::DEFAULT), enumVals(std::move(enumVals)), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+OptionEnum<std::string>::OptionEnum(const std::string & defaultValue, const std::vector<ValueType> & enumVals, FromStringFunc && fromStringFunc)
+: Option(Priority::DEFAULT), fromStringUser(std::move(fromStringFunc))
+, enumVals(enumVals), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+OptionEnum<std::string>::OptionEnum(const std::string & defaultValue, std::vector<ValueType> && enumVals, FromStringFunc && fromStringFunc)
+: Option(Priority::DEFAULT), fromStringUser(std::move(fromStringFunc))
+, enumVals(std::move(enumVals)), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+void OptionEnum<std::string>::test(const std::string & value) const
+{
+ auto it = std::find(enumVals.begin(), enumVals.end(), value);
+ if (it == enumVals.end())
+ throw InvalidValue(tfm::format(_("'%s' is not an allowed value"), value));
+}
+
+std::string OptionEnum<std::string>::fromString(const std::string & value) const
+{
+ if (fromStringUser)
+ return fromStringUser(value);
+ return value;
+}
+
+void OptionEnum<std::string>::set(Priority priority, const std::string & value)
+{
+ auto val = fromString(value);
+ if (priority >= this->priority) {
+ test(val);
+ this->value = val;
+ this->priority = priority;
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_ENUM_HPP
+#define _LIBDNF_OPTION_ENUM_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+#include <functional>
+#include <vector>
+
+namespace libdnf {
+
+template <typename T>
+class OptionEnum : public Option {
+public:
+ typedef T ValueType;
+ typedef std::function<ValueType (const std::string &)> FromStringFunc;
+
+ OptionEnum(ValueType defaultValue, const std::vector<ValueType> & enumVals);
+ OptionEnum(ValueType defaultValue, std::vector<ValueType> && enumVals);
+ OptionEnum(ValueType defaultValue, const std::vector<ValueType> & enumVals, FromStringFunc && fromStringFunc);
+ OptionEnum(ValueType defaultValue, std::vector<ValueType> && enumVals, FromStringFunc && fromStringFunc);
+ OptionEnum * clone() const override;
+ void test(ValueType value) const;
+ ValueType fromString(const std::string & value) const;
+ void set(Priority priority, ValueType value);
+ void set(Priority priority, const std::string & value) override;
+ T getValue() const;
+ T getDefaultValue() const;
+ std::string toString(ValueType value) const;
+ std::string getValueString() const override;
+ void reset() override;
+
+protected:
+ FromStringFunc fromStringUser;
+ std::vector<ValueType> enumVals;
+ ValueType defaultValue;
+ ValueType value;
+};
+
+template <>
+class OptionEnum<std::string> : public Option {
+public:
+ typedef std::string ValueType;
+ typedef std::function<ValueType (const std::string &)> FromStringFunc;
+
+ OptionEnum(const std::string & defaultValue, const std::vector<ValueType> & enumVals);
+ OptionEnum(const std::string & defaultValue, std::vector<ValueType> && enumVals);
+ OptionEnum(const std::string & defaultValue, const std::vector<ValueType> & enumVals, FromStringFunc && fromStringFunc);
+ OptionEnum(const std::string & defaultValue, std::vector<ValueType> && enumVals, FromStringFunc && fromStringFunc);
+ OptionEnum * clone() const override;
+ void test(const std::string & value) const;
+ std::string fromString(const std::string & value) const;
+ void set(Priority priority, const std::string & value) override;
+ const std::string & getValue() const;
+ const std::string & getDefaultValue() const;
+ std::string getValueString() const override;
+ void reset() override;
+
+protected:
+ FromStringFunc fromStringUser;
+ std::vector<ValueType> enumVals;
+ ValueType defaultValue;
+ ValueType value;
+};
+
+template <typename T>
+inline OptionEnum<T> * OptionEnum<T>::clone() const
+{
+ return new OptionEnum<T>(*this);
+}
+
+template <typename T>
+inline void OptionEnum<T>::reset()
+{
+ value = defaultValue;
+ priority = Priority::DEFAULT;
+}
+
+inline OptionEnum<std::string> * OptionEnum<std::string>::clone() const
+{
+ return new OptionEnum<std::string>(*this);
+}
+
+inline const std::string & OptionEnum<std::string>::getValue() const
+{
+ return value;
+}
+
+inline const std::string & OptionEnum<std::string>::getDefaultValue() const
+{
+ return defaultValue;
+}
+
+inline std::string OptionEnum<std::string>::getValueString() const
+{
+ return value;
+}
+
+inline void OptionEnum<std::string>::reset()
+{
+ value = defaultValue;
+ priority = Priority::DEFAULT;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionNumber.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+#include <limits>
+
+namespace libdnf {
+
+template <typename T>
+bool fromString(T & out, const std::string & in, std::ios_base & (*manipulator)(std::ios_base &))
+{
+ std::istringstream iss(in);
+ return !(iss >> manipulator >> out).fail();
+}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue, T min, T max)
+: Option(Priority::DEFAULT), defaultValue(defaultValue), min(min), max(max), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue, T min)
+: OptionNumber(defaultValue, min, std::numeric_limits<T>::max()) {}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue)
+: OptionNumber(defaultValue, std::numeric_limits<T>::min(), std::numeric_limits<T>::max()) {}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue, T min, T max, FromStringFunc && fromStringFunc)
+: Option(Priority::DEFAULT)
+, fromStringUser(std::move(fromStringFunc))
+, defaultValue(defaultValue), min(min), max(max), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue, T min, FromStringFunc && fromStringFunc)
+: OptionNumber(defaultValue, min, std::numeric_limits<T>::max(), std::move(fromStringFunc)) {}
+
+template <typename T>
+OptionNumber<T>::OptionNumber(T defaultValue, FromStringFunc && fromStringFunc)
+: OptionNumber(defaultValue, std::numeric_limits<T>::min(), std::numeric_limits<T>::max(), std::move(fromStringFunc)) {}
+
+template <typename T>
+void OptionNumber<T>::test(ValueType value) const
+{
+ if (value > max)
+ throw InvalidValue(tfm::format(_("given value [%d] should be less than "
+ "allowed value [%d]."), value, max));
+ else if (value < min)
+ throw InvalidValue(tfm::format(_("given value [%d] should be greater than "
+ "allowed value [%d]."), value, min));
+}
+
+template <typename T>
+T OptionNumber<T>::fromString(const std::string & value) const
+{
+ if (fromStringUser)
+ return fromStringUser(value);
+ ValueType val;
+ if (libdnf::fromString<ValueType>(val, value, std::dec))
+ return val;
+ throw InvalidValue(_("invalid value"));
+}
+
+template <typename T>
+void OptionNumber<T>::set(Priority priority, ValueType value)
+{
+ if (priority >= this->priority) {
+ test(value);
+ this->value = value;
+ this->priority = priority;
+ }
+}
+
+template <typename T>
+void OptionNumber<T>::set(Option::Priority priority, const std::string & value)
+{
+ set(priority, fromString(value));
+}
+
+template <typename T>
+std::string OptionNumber<T>::toString(ValueType value) const
+{
+ std::ostringstream oss;
+ oss << value;
+ return oss.str();
+}
+
+template class OptionNumber<std::int32_t>;
+template class OptionNumber<std::uint32_t>;
+template class OptionNumber<std::int64_t>;
+template class OptionNumber<std::uint64_t>;
+template class OptionNumber<float>;
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_NUMBER_HPP
+#define _LIBDNF_OPTION_NUMBER_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+#include <cstdint>
+#include <functional>
+
+namespace libdnf {
+
+template <typename T>
+class OptionNumber : public Option {
+public:
+ typedef T ValueType;
+ typedef std::function<ValueType (const std::string &)> FromStringFunc;
+
+ OptionNumber(T defaultValue, T min, T max);
+ OptionNumber(T defaultValue, T min);
+ OptionNumber(T defaultValue);
+ OptionNumber(T defaultValue, T min, T max, FromStringFunc && fromStringFunc);
+ OptionNumber(T defaultValue, T min, FromStringFunc && fromStringFunc);
+ OptionNumber(T defaultValue, FromStringFunc && fromStringFunc);
+ OptionNumber * clone() const override;
+ void test(ValueType value) const;
+ T fromString(const std::string & value) const;
+ void set(Priority priority, ValueType value);
+ void set(Priority priority, const std::string & value) override;
+ T getValue() const;
+ T getDefaultValue() const;
+ std::string toString(ValueType value) const;
+ std::string getValueString() const override;
+ void reset() override;
+
+protected:
+ FromStringFunc fromStringUser;
+ ValueType defaultValue;
+ ValueType min;
+ ValueType max;
+ ValueType value;
+};
+
+template <typename T>
+inline OptionNumber<T> * OptionNumber<T>::clone() const
+{
+ return new OptionNumber<T>(*this);
+}
+
+template <typename T>
+inline T OptionNumber<T>::getValue() const
+{
+ return value;
+}
+
+template <typename T>
+inline T OptionNumber<T>::getDefaultValue() const
+{
+ return defaultValue;
+}
+
+template <typename T>
+inline std::string OptionNumber<T>::getValueString() const
+{
+ return toString(value);
+}
+
+template <typename T>
+inline void OptionNumber<T>::reset()
+{
+ value = defaultValue;
+ priority = Priority::DEFAULT;
+}
+
+extern template class OptionNumber<std::int32_t>;
+extern template class OptionNumber<std::uint32_t>;
+extern template class OptionNumber<std::int64_t>;
+extern template class OptionNumber<std::uint64_t>;
+extern template class OptionNumber<float>;
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionPath.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace libdnf {
+
+static std::string removeFileProt(const std::string & value)
+{
+ if (value.compare(0, 7, "file://") == 0)
+ return value.substr(7);
+ return value;
+}
+
+OptionPath::OptionPath(const std::string & defaultValue, bool exists, bool absPath)
+: OptionString(defaultValue), exists(exists), absPath(absPath)
+{
+ this->defaultValue = removeFileProt(this->defaultValue);
+ test(this->defaultValue);
+ this->value = this->defaultValue;
+}
+
+OptionPath::OptionPath(const char * defaultValue, bool exists, bool absPath)
+: OptionString(defaultValue), exists(exists), absPath(absPath)
+{
+ if (defaultValue) {
+ this->defaultValue = removeFileProt(this->defaultValue);
+ test(this->defaultValue);
+ this->value = this->defaultValue;
+ }
+}
+
+OptionPath::OptionPath(const std::string & defaultValue, const std::string & regex, bool icase, bool exists, bool absPath)
+: OptionString(removeFileProt(defaultValue), regex, icase), exists(exists), absPath(absPath)
+{
+ this->defaultValue = removeFileProt(this->defaultValue);
+ test(this->defaultValue);
+ this->value = this->defaultValue;
+}
+
+OptionPath::OptionPath(const char * defaultValue, const std::string & regex, bool icase, bool exists, bool absPath)
+: OptionString(defaultValue, regex, icase), exists(exists), absPath(absPath)
+{
+ if (defaultValue) {
+ this->defaultValue = removeFileProt(this->defaultValue);
+ test(this->defaultValue);
+ this->value = this->defaultValue;
+ }
+}
+
+void OptionPath::test(const std::string & value) const
+{
+ if (absPath && value[0] != '/')
+ throw InvalidValue(tfm::format(_("given path '%s' is not absolute."), value));
+
+ struct stat buffer;
+ if (exists && stat(value.c_str(), &buffer))
+ throw InvalidValue(tfm::format(_("given path '%s' does not exist."), value));
+}
+
+void OptionPath::set(Priority priority, const std::string & value)
+{
+ if (priority >= this->priority) {
+ OptionString::test(value);
+ auto val = removeFileProt(value);
+ test(val);
+ this->value = val;
+ this->priority = priority;
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_PATH_HPP
+#define _LIBDNF_OPTION_PATH_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "OptionString.hpp"
+
+namespace libdnf {
+
+/**
+* @class OptionPath
+*
+* @brief Option for file path which can validate path existence.
+*
+*/
+class OptionPath : public OptionString {
+public:
+ OptionPath(const std::string & defaultValue, bool exists = false, bool absPath = false);
+ OptionPath(const char * defaultValue, bool exists = false, bool absPath = false);
+ OptionPath(const std::string & defaultValue, const std::string & regex, bool icase, bool exists = false, bool absPath = false);
+ OptionPath(const char * defaultValue, const std::string & regex, bool icase, bool exists = false, bool absPath = false);
+ OptionPath * clone() const override;
+ void test(const std::string & value) const;
+ void set(Priority priority, const std::string & value) override;
+
+protected:
+ bool exists;
+ bool absPath;
+};
+
+inline OptionPath * OptionPath::clone() const
+{
+ return new OptionPath(*this);
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionSeconds.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+namespace libdnf {
+
+OptionSeconds::OptionSeconds(ValueType defaultValue, ValueType min, ValueType max)
+: OptionNumber(defaultValue, min, max) {}
+
+OptionSeconds::OptionSeconds(ValueType defaultValue, ValueType min)
+: OptionNumber(defaultValue, min) {}
+
+OptionSeconds::OptionSeconds(ValueType defaultValue)
+: OptionNumber(defaultValue) {}
+
+OptionSeconds::ValueType OptionSeconds::fromString(const std::string & value) const
+{
+ if (value.empty())
+ throw InvalidValue(_("no value specified"));
+
+ if (value == "-1" || value == "never") // Special cache timeout, meaning never
+ return -1;
+
+ std::size_t idx;
+ auto res = std::stod(value, &idx);
+ if (res < 0)
+ throw InvalidValue(tfm::format(_("seconds value '%s' must not be negative"), value));
+
+ if (idx < value.length()) {
+ if (idx < value.length() - 1)
+ throw InvalidValue(tfm::format(_("could not convert '%s' to seconds"), value));
+ switch (value.back()) {
+ case 's': case 'S':
+ break;
+ case 'm': case 'M':
+ res *= 60;
+ break;
+ case 'h': case 'H':
+ res *= 60 * 60;
+ break;
+ case 'd': case 'D':
+ res *= 60 * 60 * 24;
+ break;
+ default:
+ throw InvalidValue(tfm::format(_("unknown unit '%s'"), value.back()));
+ }
+ }
+
+ return res;
+}
+
+void OptionSeconds::set(Priority priority, const std::string & value)
+{
+ set(priority, fromString(value));
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_SECONDS_HPP
+#define _LIBDNF_OPTION_SECONDS_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "OptionNumber.hpp"
+
+#include <cstdint>
+
+namespace libdnf {
+
+/**
+* @class OptionSeconds
+*
+* @brief An option representing an integer value of seconds.
+*
+* Valid inputs: 100, 1.5m, 90s, 1.2d, 1d, 0xF, 0.1, -1, never.
+* Invalid inputs: -10, -0.1, 45.6Z, 1d6h, 1day, 1y.
+*/
+class OptionSeconds : public OptionNumber<std::int32_t> {
+public:
+ OptionSeconds(ValueType defaultValue, ValueType min, ValueType max);
+ OptionSeconds(ValueType defaultValue, ValueType min);
+ OptionSeconds(ValueType defaultValue);
+ OptionSeconds * clone() const override;
+ ValueType fromString(const std::string & value) const;
+ using OptionNumber<std::int32_t>::set;
+ void set(Priority priority, const std::string & value) override;
+};
+
+inline OptionSeconds * OptionSeconds::clone() const
+{
+ return new OptionSeconds(*this);
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionString.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "regex/regex.hpp"
+
+namespace libdnf {
+
+OptionString::OptionString(const std::string & defaultValue)
+: Option(Priority::DEFAULT), initPriority(Priority::DEFAULT), defaultValue(defaultValue), value(defaultValue) {}
+
+OptionString::OptionString(const char * defaultValue)
+{
+ if (defaultValue) {
+ this->value = this->defaultValue = defaultValue;
+ this->initPriority = this->priority = Priority::DEFAULT;
+ } else {
+ this->initPriority = Priority::EMPTY;
+ }
+}
+
+OptionString::OptionString(const std::string & defaultValue, const std::string & regex, bool icase)
+: Option(Priority::DEFAULT), initPriority(Priority::DEFAULT), regex(regex), icase(icase)
+, defaultValue(defaultValue), value(defaultValue) { test(defaultValue); }
+
+OptionString::OptionString(const char * defaultValue, const std::string & regex, bool icase)
+: regex(regex), icase(icase)
+{
+ if (defaultValue) {
+ this->defaultValue = defaultValue;
+ test(this->defaultValue);
+ this->value = this->defaultValue;
+ this->priority = Priority::DEFAULT;
+ } else {
+ this->initPriority = Priority::EMPTY;
+ }
+}
+
+void OptionString::test(const std::string & value) const
+{
+ if (regex.empty())
+ return;
+ if (!Regex(regex.c_str(), (icase ? REG_ICASE : 0) | REG_EXTENDED | REG_NOSUB).match(value.c_str()))
+ throw InvalidValue(tfm::format(_("'%s' is not an allowed value"), value));
+}
+
+void OptionString::set(Priority priority, const std::string & value)
+{
+ if (priority >= this->priority) {
+ test(value);
+ this->value = value;
+ this->priority = priority;
+ }
+}
+
+const std::string & OptionString::getValue() const
+{
+ if (priority == Priority::EMPTY)
+ throw ValueNotSet(_("GetValue(): Value not set"));
+ return value;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_STRING_HPP
+#define _LIBDNF_OPTION_STRING_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+
+namespace libdnf {
+
+class OptionString : public Option {
+public:
+ typedef std::string ValueType;
+
+ OptionString(const std::string & defaultValue);
+ OptionString(const char * defaultValue);
+ OptionString(const std::string & defaultValue, const std::string & regex, bool icase);
+ OptionString(const char * defaultValue, const std::string & regex, bool icase);
+ OptionString * clone() const override;
+ void test(const std::string & value) const;
+ void set(Priority priority, const std::string & value) override;
+ std::string fromString(const std::string & value) const;
+ const std::string & getValue() const;
+ const std::string & getDefaultValue() const noexcept;
+ std::string getValueString() const override;
+ void reset() override;
+
+protected:
+ Priority initPriority;
+ std::string regex;
+ bool icase;
+ std::string defaultValue;
+ std::string value;
+};
+
+inline OptionString * OptionString::clone() const
+{
+ return new OptionString(*this);
+}
+
+inline const std::string & OptionString::getDefaultValue() const noexcept
+{
+ return defaultValue;
+}
+
+inline std::string OptionString::getValueString() const
+{
+ return getValue();
+}
+
+inline std::string OptionString::fromString(const std::string & value) const
+{
+ return value;
+}
+
+inline void OptionString::reset()
+{
+ value = defaultValue;
+ priority = initPriority;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "OptionStringList.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "regex/regex.hpp"
+
+namespace libdnf {
+
+OptionStringList::OptionStringList(const ValueType & defaultValue)
+: Option(Priority::DEFAULT), defaultValue(defaultValue), value(defaultValue) {}
+
+OptionStringList::OptionStringList(const ValueType & defaultValue, const std::string & regex, bool icase)
+: Option(Priority::DEFAULT), regex(regex), icase(icase), defaultValue(defaultValue), value(defaultValue)
+{
+ test(defaultValue);
+}
+
+OptionStringList::OptionStringList(const std::string & defaultValue)
+: Option(Priority::DEFAULT)
+{
+ this->value = this->defaultValue = fromString(defaultValue);
+}
+
+OptionStringList::OptionStringList(const std::string & defaultValue, const std::string & regex, bool icase)
+: Option(Priority::DEFAULT), regex(regex), icase(icase)
+{
+ this->defaultValue = fromString(defaultValue);
+ test(this->defaultValue);
+ value = this->defaultValue;
+}
+
+void OptionStringList::test(const std::vector<std::string> & value) const
+{
+ if (regex.empty())
+ return;
+ Regex regexObj(regex.c_str(), (icase ? REG_ICASE : 0) | REG_EXTENDED | REG_NOSUB);
+ for (const auto & val : value) {
+ if (!regexObj.match(val.c_str()))
+ throw InvalidValue(tfm::format(_("'%s' is not an allowed value"), val));
+ }
+}
+
+OptionStringList::ValueType OptionStringList::fromString(const std::string & value) const
+{
+ std::vector<std::string> tmp;
+ auto start = value.find_first_not_of(" ");
+ while (start != value.npos && start < value.length()) {
+ auto end = value.find_first_of(" ,\n", start);
+ if (end == value.npos) {
+ tmp.push_back(value.substr(start));
+ break;
+ }
+ tmp.push_back(value.substr(start, end - start));
+ start = value.find_first_not_of(" ", end + 1);
+ if (start != value.npos && value[start] == ',' && value[end] == ' ') {
+ end = start;
+ start = value.find_first_not_of(" ", start + 1);
+ }
+ if (start != value.npos && value[start] == '\n' && (value[end] == ' ' || value[end] == ','))
+ start = value.find_first_not_of(" ", start + 1);
+ }
+ return tmp;
+}
+
+void OptionStringList::set(Priority priority, const ValueType & value)
+{
+ if (priority >= this->priority) {
+ test(value);
+ this->value = value;
+ this->priority = priority;
+ }
+}
+
+void OptionStringList::set(Priority priority, const std::string & value)
+{
+ set(priority, fromString(value));
+}
+
+std::string OptionStringList::toString(const ValueType & value) const
+{
+ std::ostringstream oss;
+ bool next{false};
+ for (auto & val : value) {
+ if (next)
+ oss << ", ";
+ else
+ next = true;
+ oss << val;
+ }
+ return oss.str();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_OPTION_STRING_LIST_HPP
+#define _LIBDNF_OPTION_STRING_LIST_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include "Option.hpp"
+#include <vector>
+
+namespace libdnf {
+
+class OptionStringList : public Option {
+public:
+ typedef std::vector<std::string> ValueType;
+
+ OptionStringList(const ValueType & defaultValue);
+ OptionStringList(const ValueType & defaultValue, const std::string & regex, bool icase);
+ OptionStringList(const std::string & defaultValue);
+ OptionStringList(const std::string & defaultValue, const std::string & regex, bool icase);
+ OptionStringList * clone() const override;
+ void test(const std::vector<std::string> & value) const;
+ ValueType fromString(const std::string & value) const;
+ virtual void set(Priority priority, const ValueType & value);
+ void set(Priority priority, const std::string & value) override;
+ const ValueType & getValue() const;
+ const ValueType & getDefaultValue() const;
+ std::string toString(const ValueType & value) const;
+ std::string getValueString() const override;
+ void reset() override;
+
+protected:
+ std::string regex;
+ bool icase;
+ ValueType defaultValue;
+ ValueType value;
+};
+
+inline OptionStringList * OptionStringList::clone() const
+{
+ return new OptionStringList(*this);
+}
+
+inline const OptionStringList::ValueType & OptionStringList::getValue() const
+{
+ return value;
+}
+
+inline const OptionStringList::ValueType & OptionStringList::getDefaultValue() const
+{
+ return defaultValue;
+}
+
+inline std::string OptionStringList::getValueString() const
+{
+ return toString(value);
+}
+
+inline void OptionStringList::reset()
+{
+ value = defaultValue;
+ priority = Priority::DEFAULT;
+}
+
+}
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
+#define _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
+
+#define DEFAULT_PLUGINS_DIRECTORY "@CMAKE_INSTALL_FULL_LIBDIR@/libdnf/plugins/"
+
+#endif // _LIBDNF_CONFIG_@MULTILIB_ARCH@_H_
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <limits.h>
+
+#if (ULONG_MAX == 0xffffffffffffffff)
+#include "config-64.h"
+#elif (ULONG_MAX == 0xffffffff)
+#include "config-32.h"
+#else
+#error "Unknown word size"
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DNF_ADVISORY_KIND_PRIVATE_H
+#define DNF_ADVISORY_KIND_PRIVATE_H
+
+#include <solv/pool.h>
+
+#include "dnf-advisory.h"
+#include "dnf-types.h"
+
+#define SOLVABLE_NAME_ADVISORY_PREFIX "patch:"
+
+DnfAdvisory *dnf_advisory_new (DnfSack *sack, Id a_id);
+
+#endif // DNF_ADVISORY_KIND_PRIVATE_H
--- /dev/null
+/*
+ * Copyright (C) 2014-2018 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-advisory
+ * @short_description: Update advisory
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * This object represents a single update.
+ *
+ * See also: #DnfContext
+ */
+
+
+#include "dnf-advisory-private.hpp"
+#include "dnf-advisorypkg.h"
+#include "dnf-advisoryref.h"
+#include "sack/advisory.hpp"
+#include "sack/advisoryref.hpp"
+#include "sack/advisorypkg.hpp"
+
+
+/**
+ * dnf_advisory_new:
+ *
+ * Creates a new #DnfAdvisory.
+ *
+ * Returns:(transfer full): a #DnfAdvisory
+ *
+ * Since: 0.7.0
+ **/
+DnfAdvisory *
+dnf_advisory_new(DnfSack *sack, Id a_id)
+{
+ return new libdnf::Advisory(sack, a_id);
+}
+
+/**
+ * dnf_advisory_free:
+ *
+ * Destructor of #DnfAdvisory.
+ *
+ * Since: 0.13.0
+ **/
+void
+dnf_advisory_free(DnfAdvisory *advisory)
+{
+ delete advisory;
+}
+
+/**
+ * dnf_advisory_compare:
+ * @left: a #DnfAdvisory instance.
+ * @right: another #DnfAdvisory instance.
+ *
+ * Compares two #DnfAdvisory objects for equality.
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_advisory_compare(DnfAdvisory *left, DnfAdvisory *right)
+{
+ return left == right;
+}
+
+/**
+ * dnf_advisory_get_title:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the title assigned to the advisory.
+ *
+ * Returns: a string value, or %NULL for unset
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisory_get_title(DnfAdvisory *advisory)
+{
+ return advisory->getTitle();
+}
+
+/**
+ * dnf_advisory_get_id:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the ID assigned to the advisory.
+ *
+ * Returns: a string value, or %NULL for unset
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisory_get_id(DnfAdvisory *advisory)
+{
+ return advisory->getName();
+}
+
+/**
+ * dnf_advisory_get_kind:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the advisory kind.
+ *
+ * Returns: a #DnfAdvisoryKind, e.g. %DNF_ADVISORY_KIND_BUGFIX
+ *
+ * Since: 0.7.0
+ */
+DnfAdvisoryKind
+dnf_advisory_get_kind(DnfAdvisory *advisory)
+{
+ return advisory->getKind();
+}
+
+/**
+ * dnf_advisory_get_description:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the advisory description.
+ *
+ * Returns: a string value, or %NULL for unset
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisory_get_description(DnfAdvisory *advisory)
+{
+ return advisory->getDescription();
+}
+
+/**
+ * dnf_advisory_get_rights:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the update rights for the advisory.
+ *
+ * Returns: a string value, or %NULL for unset
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisory_get_rights(DnfAdvisory *advisory)
+{
+ return advisory->getRights();
+}
+
+/**
+ * dnf_advisory_get_severity:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the advisory severity.
+ *
+ * Returns: a string value, or %NULL for unset
+ *
+ * Since: 0.8.0
+ */
+const char *
+dnf_advisory_get_severity(DnfAdvisory *advisory)
+{
+ return advisory->getSeverity();
+}
+
+/**
+ * dnf_advisory_get_updated:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets the timestamp when the advisory was created.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_advisory_get_updated(DnfAdvisory *advisory)
+{
+ return advisory->getUpdated();
+}
+
+/**
+ * dnf_advisory_get_packages:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets any packages referenced by the advisory.
+ *
+ * Returns: (transfer container) (element-type DnfAdvisoryPkg): a list of packages
+ *
+ * Since: 0.7.0
+ */
+GPtrArray *
+dnf_advisory_get_packages(DnfAdvisory *advisory)
+{
+ std::vector<libdnf::AdvisoryPkg> pkgsvector;
+ advisory->getPackages(pkgsvector);
+
+ GPtrArray *pkglist = g_ptr_array_new_with_free_func((GDestroyNotify) dnf_advisorypkg_free);
+ for (auto& advisorypkg : pkgsvector) {
+ g_ptr_array_add(pkglist, new libdnf::AdvisoryPkg(std::move(advisorypkg)));
+ }
+ return pkglist;
+}
+
+/**
+ * dnf_advisory_get_references:
+ * @advisory: a #DnfAdvisory instance.
+ *
+ * Gets any references referenced by the advisory.
+ *
+ * Returns: (transfer container) (element-type DnfAdvisoryRef): a list of references
+ *
+ * Since: 0.7.0
+ */
+GPtrArray *
+dnf_advisory_get_references(DnfAdvisory *advisory)
+{
+ std::vector<libdnf::AdvisoryRef> refsvector;
+ advisory->getReferences(refsvector);
+
+ GPtrArray *reflist = g_ptr_array_new_with_free_func((GDestroyNotify) dnf_advisoryref_free);
+ for (const auto& advisoryref : refsvector) {
+ g_ptr_array_add(reflist, new libdnf::AdvisoryRef(advisoryref));
+ }
+ return reflist;
+}
+
+
+/**
+ * dnf_advisory_match_id:
+ * @advisory: a #DnfAdvisory instance.
+ * @s: string
+ *
+ * Matches #DnfAdvisory id against string
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_advisory_match_id(DnfAdvisory *advisory, const char *s)
+{
+ return advisory->matchName(s);
+}
+
+/**
+ * dnf_advisory_match_kind:
+ * @advisory: a #DnfAdvisory instance.
+ * @s: string
+ *
+ * Matches #DnfAdvisory kind against string
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_advisory_match_kind(DnfAdvisory *advisory, const char *s)
+{
+ return advisory->matchKind(s);
+}
+
+/**
+ * dnf_advisory_match_severity:
+ * @advisory: a #DnfAdvisory instance.
+ * @s: string
+ *
+ * Matches #DnfAdvisory severity against string
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.8.0
+ */
+gboolean
+dnf_advisory_match_severity(DnfAdvisory *advisory, const char *s)
+{
+ return advisory->matchSeverity(s);
+}
+
+/**
+ * dnf_advisory_match_cve:
+ * @advisory: a #DnfAdvisory instance.
+ * @s: string
+ *
+ * Matches if #DnfAdvisoryRef has a #DnfAdvisoryRef which is CVE
+ * and matches against string
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_advisory_match_cve(DnfAdvisory *advisory, const char *s)
+{
+ return advisory->matchCVE(s);
+}
+
+/**
+ * dnf_advisory_match_bug:
+ * @advisory: a #DnfAdvisory instance.
+ * @s: string
+ *
+ * Matches if #DnfAdvisoryRef has a #DnfAdvisoryRef which is bug
+ * and matches against string
+ *
+ * Returns: %TRUE if they are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_advisory_match_bug(DnfAdvisory *advisory, const char *s)
+{
+ return advisory->matchBug(s);
+}
--- /dev/null
+/*
+ * Copyright (C) 2014-2018 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_ADVISORY_H
+#define __DNF_ADVISORY_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct Advisory;
+}
+typedef struct libdnf::Advisory DnfAdvisory;
+#else
+typedef struct Advisory DnfAdvisory;
+#endif
+
+typedef enum {
+ DNF_ADVISORY_KIND_UNKNOWN = 0, /* ordered by rough importance */
+ DNF_ADVISORY_KIND_SECURITY = 1,
+ DNF_ADVISORY_KIND_BUGFIX = 2,
+ DNF_ADVISORY_KIND_ENHANCEMENT = 3,
+ DNF_ADVISORY_KIND_NEWPACKAGE = 4
+} DnfAdvisoryKind;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void dnf_advisory_free(DnfAdvisory *advisory);
+const char *dnf_advisory_get_title (DnfAdvisory *advisory);
+const char *dnf_advisory_get_id (DnfAdvisory *advisory);
+DnfAdvisoryKind dnf_advisory_get_kind (DnfAdvisory *advisory);
+const char *dnf_advisory_get_description (DnfAdvisory *advisory);
+const char *dnf_advisory_get_rights (DnfAdvisory *advisory);
+const char *dnf_advisory_get_severity (DnfAdvisory *advisory);
+guint64 dnf_advisory_get_updated (DnfAdvisory *advisory);
+GPtrArray *dnf_advisory_get_packages (DnfAdvisory *advisory);
+GPtrArray *dnf_advisory_get_references (DnfAdvisory *advisory);
+int dnf_advisory_compare (DnfAdvisory *left,
+ DnfAdvisory *right);
+gboolean dnf_advisory_match_id (DnfAdvisory *advisory,
+ const char *s);
+gboolean dnf_advisory_match_kind (DnfAdvisory *advisory,
+ const char *s);
+gboolean dnf_advisory_match_severity (DnfAdvisory *advisory,
+ const char *s);
+gboolean dnf_advisory_match_cve (DnfAdvisory *advisory,
+ const char *s);
+gboolean dnf_advisory_match_bug (DnfAdvisory *advisory,
+ const char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_ADVISORY_H */
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-advisorypkg
+ * @short_description: Update advisory package
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * This object represents an package listed as an advisory.
+ *
+ * See also: #DnfAdvisory
+ */
+
+#include "dnf-advisorypkg.h"
+#include "sack/advisorypkg.hpp"
+
+
+/**
+ * dnf_advisorypkg_compare:
+ * @left: a #DnfAdvisoryPkg instance.
+ * @right: another #DnfAdvisoryPkg instance.
+ *
+ * Compares one advisory against another.
+ *
+ * Returns: 0 if they are the same
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_advisorypkg_compare(DnfAdvisoryPkg *left, DnfAdvisoryPkg *right)
+{
+ return !left->nevraEQ(*right);
+}
+
+/**
+ * dnf_advisorypkg_compare_solvable:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ * @pool: package pool
+ * @solvable: solvable
+ *
+ * Compares advisorypkg against solvable
+ *
+ * Returns: 0 if they are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_advisorypkg_compare_solvable(DnfAdvisoryPkg *advisorypkg, Pool *pool, Solvable *s)
+{
+ return !advisorypkg->nevraEQ(s);
+}
+
+DnfAdvisory *
+dnf_advisorypkg_get_advisory (DnfAdvisoryPkg *advisorypkg)
+{
+ return advisorypkg->getAdvisory();
+}
+
+/**
+ * dnf_advisorypkg_free:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ *
+ * Destructor of #DnfAdvisoryPkg
+ *
+ * Since: 0.13.0
+ */
+void
+dnf_advisorypkg_free(DnfAdvisoryPkg *advisorypkg)
+{
+ delete advisorypkg;
+}
+
+/**
+ * dnf_advisorypkg_get_name:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ *
+ * Returns the advisory package name.
+ *
+ * Returns: string, or %NULL.
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisorypkg_get_name(DnfAdvisoryPkg *advisorypkg)
+{
+ return advisorypkg->getNameString();
+}
+
+/**
+ * dnf_advisorypkg_get_evr:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ *
+ * Returns the advisory package EVR.
+ *
+ * Returns: string, or %NULL.
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisorypkg_get_evr(DnfAdvisoryPkg *advisorypkg)
+{
+ return advisorypkg->getEVRString();
+}
+
+/**
+ * dnf_advisorypkg_get_arch:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ *
+ * Returns the advisory package architecture.
+ *
+ * Returns: string, or %NULL.
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisorypkg_get_arch(DnfAdvisoryPkg *advisorypkg)
+{
+ return advisorypkg->getArchString();
+}
+
+/**
+ * dnf_advisorypkg_get_filename:
+ * @advisorypkg: a #DnfAdvisoryPkg instance.
+ *
+ * Returns the advisory package filename.
+ *
+ * Returns: string, or %NULL.
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisorypkg_get_filename(DnfAdvisoryPkg *advisorypkg)
+{
+ return advisorypkg->getFileName();
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_ADVISORYPKG_H
+#define __DNF_ADVISORYPKG_H
+
+#include "dnf-advisory.h"
+
+#include <solv/pool.h>
+#include <glib-object.h>
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct AdvisoryPkg;
+}
+typedef struct libdnf::AdvisoryPkg DnfAdvisoryPkg;
+#else
+typedef struct AdvisoryPkg DnfAdvisoryPkg;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void dnf_advisorypkg_free (DnfAdvisoryPkg *advisorypkg);
+const char *dnf_advisorypkg_get_name (DnfAdvisoryPkg *advisorypkg);
+const char *dnf_advisorypkg_get_evr (DnfAdvisoryPkg *advisorypkg);
+const char *dnf_advisorypkg_get_arch (DnfAdvisoryPkg *advisorypkg);
+const char *dnf_advisorypkg_get_filename (DnfAdvisoryPkg *advisorypkg);
+
+int dnf_advisorypkg_compare (DnfAdvisoryPkg *left,
+ DnfAdvisoryPkg *right);
+gboolean dnf_advisorypkg_compare_solvable (DnfAdvisoryPkg *advisorypkg,
+ Pool *pool,
+ Solvable *s);
+DnfAdvisory * dnf_advisorypkg_get_advisory (DnfAdvisoryPkg *advisorypkg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_ADVISORYPKG_H */
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_ADVISORYREF_PRIVATE_H
+#define __DNF_ADVISORYREF_PRIVATE_H
+
+#include <solv/pool.h>
+
+#include "dnf-advisoryref.h"
+#include "dnf-types.h"
+
+DnfAdvisoryRef *dnf_advisoryref_new(DnfSack *sack, Id a_id, int index);
+
+#endif // __DNF_ADVISORYREF_PRIVATE_H
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/**
+ * SECTION:dnf-advisoryref
+ * @short_description: Update advisory reference
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * This object represents a reference given to an update.
+ *
+ * See also: #DnfContext
+ */
+
+
+#include <solv/repo.h>
+#include <solv/util.h>
+#include <glib-object.h>
+
+#include "dnf-advisoryref-private.hpp"
+#include "dnf-sack-private.hpp"
+#include "sack/advisoryref.hpp"
+
+/**
+ * dnf_advisoryref_new:
+ *
+ * Creates a new #DnfAdvisoryRef.
+ *
+ * Returns:(transfer full): a #DnfAdvisoryRef
+ *
+ * Since: 0.7.0
+ **/
+DnfAdvisoryRef *
+dnf_advisoryref_new(DnfSack *sack, Id a_id, int index)
+{
+ return new libdnf::AdvisoryRef(sack, a_id, index);
+}
+
+/**
+ * dnf_advisoryref_free:
+ *
+ * Destructor of #DnfAdvisoryRef.
+ *
+ * Since: 0.13.0
+ **/
+void
+dnf_advisoryref_free(DnfAdvisoryRef *advisoryref)
+{
+ delete advisoryref;
+}
+
+/**
+ * dnf_advisoryref_compare:
+ * @left: a #DnfAdvisoryRef instance.
+ * @right: another #DnfAdvisoryRef instance.
+ *
+ * Checks two #DnfAdvisoryRef objects for equality.
+ *
+ * Returns: TRUE if the #DnfAdvisoryRef objects are the same
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_advisoryref_compare(DnfAdvisoryRef *left, DnfAdvisoryRef *right)
+{
+ return *left == *right;
+}
+
+static const char *
+advisoryref_get_str(DnfAdvisoryRef *advisoryref, Id keyname)
+{
+ Dataiterator di;
+ const char *str = NULL;
+ int count = 0;
+ Pool *pool = dnf_sack_get_pool(advisoryref->getDnfSack());
+
+ dataiterator_init(&di, pool, 0, advisoryref->getAdvisory(), UPDATE_REFERENCE, 0, 0);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos(&di);
+ if (count++ == advisoryref->getIndex()) {
+ str = pool_lookup_str(pool, SOLVID_POS, keyname);
+ break;
+ }
+ }
+ dataiterator_free(&di);
+
+ return str;
+}
+
+/**
+ * dnf_advisoryref_get_kind:
+ * @advisoryref: a #DnfAdvisoryRef instance.
+ *
+ * Gets the kind of advisory reference.
+ *
+ * Returns: a #DnfAdvisoryRef, e.g. %DNF_REFERENCE_KIND_BUGZILLA
+ *
+ * Since: 0.7.0
+ */
+DnfAdvisoryRefKind
+dnf_advisoryref_get_kind(DnfAdvisoryRef *advisoryref)
+{
+ const char *type;
+ type = advisoryref_get_str(advisoryref, UPDATE_REFERENCE_TYPE);
+ if (type == NULL)
+ return DNF_REFERENCE_KIND_UNKNOWN;
+ if (!g_strcmp0 (type, "bugzilla"))
+ return DNF_REFERENCE_KIND_BUGZILLA;
+ if (!g_strcmp0 (type, "cve"))
+ return DNF_REFERENCE_KIND_CVE;
+ if (!g_strcmp0 (type, "vendor"))
+ return DNF_REFERENCE_KIND_VENDOR;
+ return DNF_REFERENCE_KIND_UNKNOWN;
+}
+
+/**
+ * dnf_advisoryref_get_id:
+ * @advisoryref: a #DnfAdvisoryRef instance.
+ *
+ * Gets an ID for the advisory.
+ *
+ * Returns: the advisory ID
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisoryref_get_id(DnfAdvisoryRef *advisoryref)
+{
+ return advisoryref_get_str(advisoryref, UPDATE_REFERENCE_ID);
+}
+
+/**
+ * dnf_advisoryref_get_title:
+ * @advisoryref: a #DnfAdvisoryRef instance.
+ *
+ * Gets a title to use for the advisory.
+ *
+ * Returns: the advisory title
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisoryref_get_title(DnfAdvisoryRef *advisoryref)
+{
+ return advisoryref_get_str(advisoryref, UPDATE_REFERENCE_TITLE);
+}
+
+/**
+ * dnf_advisoryref_get_url:
+ * @advisoryref: a #DnfAdvisoryRef instance.
+ *
+ * Gets the link for the advisory.
+ *
+ * Returns: the advisory URL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_advisoryref_get_url(DnfAdvisoryRef *advisoryref)
+{
+ return advisoryref_get_str(advisoryref, UPDATE_REFERENCE_HREF);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_ADVISORYREF_H
+#define __DNF_ADVISORYREF_H
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct AdvisoryRef;
+}
+typedef struct libdnf::AdvisoryRef DnfAdvisoryRef;
+#else
+typedef struct AdvisoryRef DnfAdvisoryRef;
+#endif
+
+
+typedef enum {
+ DNF_REFERENCE_KIND_UNKNOWN = 0,
+ DNF_REFERENCE_KIND_BUGZILLA = 1,
+ DNF_REFERENCE_KIND_CVE = 2,
+ DNF_REFERENCE_KIND_VENDOR = 3
+} DnfAdvisoryRefKind;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void dnf_advisoryref_free(DnfAdvisoryRef *advisoryref);
+DnfAdvisoryRefKind dnf_advisoryref_get_kind (DnfAdvisoryRef *advisoryref);
+const char *dnf_advisoryref_get_id (DnfAdvisoryRef *advisoryref);
+const char *dnf_advisoryref_get_title (DnfAdvisoryRef *advisoryref);
+const char *dnf_advisoryref_get_url (DnfAdvisoryRef *advisoryref);
+int dnf_advisoryref_compare (DnfAdvisoryRef *left,
+ DnfAdvisoryRef *right);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_ADVISORYREF_H */
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dnf-conf.h"
+
+#include "dnf-context.hpp"
+
+/**
+ * dnf_conf_main_get_option:
+ * @opt_name: option name
+ * @priority: pointer to priority - output value
+ * @error: A #GError or %NULL
+ *
+ * Gets option value and priority.
+ *
+ * Returns: string value or %NULL, %NULL means error
+ *
+ * Since: 0.56.0
+ **/gchar *
+dnf_conf_main_get_option(const gchar * name, enum DnfConfPriority * priority, GError ** error)
+{
+ auto & optBinds = libdnf::getGlobalMainConfig().optBinds();
+ auto optBindsIter = optBinds.find(name);
+
+ if (optBindsIter == optBinds.end()) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_UNKNOWN_OPTION, "Unknown option \"%s\"", name);
+ return NULL;
+ }
+
+ try {
+ gchar * ret = g_strdup(optBindsIter->second.getValueString().c_str());
+ *priority = static_cast<DnfConfPriority>(optBindsIter->second.getPriority());
+ return ret;
+ } catch (const std::exception & ex) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "Option \"%s\": %s", name, ex.what());
+ return NULL;
+ }
+}
+
+/**
+ * dnf_conf_main_set_option:
+ * @opt_name: option name
+ * @priority: priority
+ * @value: string value
+ * @error: A #GError or %NULL
+ *
+ * Sets option value and priority.
+ *
+ * Returns: %TRUE if option opt_name was set, %FALSE means error - error value is set
+ *
+ * Since: 0.56.0
+ **/
+gboolean
+dnf_conf_main_set_option(const gchar * name, enum DnfConfPriority priority, const gchar * value, GError ** error)
+{
+ auto & optBinds = libdnf::getGlobalMainConfig().optBinds();
+ auto optBindsIter = optBinds.find(name);
+
+ if (optBindsIter == optBinds.end()) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_UNKNOWN_OPTION, "Unknown option \"%s\"", name);
+ return FALSE;
+ }
+
+ try {
+ optBindsIter->second.newString(static_cast<libdnf::Option::Priority>(priority), value);
+ } catch (const std::exception & ex) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID, "Option \"%s\": %s", name, ex.what());
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * dnf_conf_add_setopt:
+ * @key: opton_name or repo_id.option_name (repo_id can contain globs)
+ * @priority: priority
+ * @value: string value
+ * @error: A #GError or %NULL
+ *
+ * Add setopt. Supports also repositories options.
+ *
+ * Returns: %TRUE setopt was accepted, %FALSE means error - setopt was not accepted
+ *
+ * Since: 0.56.0
+ **/
+gboolean
+dnf_conf_add_setopt(const gchar * key, enum DnfConfPriority priority, const gchar * value, GError ** error)
+{
+ return libdnf::addSetopt(key, static_cast<libdnf::Option::Priority>(priority), value, error);
+}
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _DNF_CONF_H_
+#define _DNF_CONF_H_
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* redefined: enum class libdnf::Option::Priority */
+enum DnfConfPriority {
+ DNF_CONF_EMPTY = 0,
+ DNF_CONF_DEFAULT = 10,
+ DNF_CONF_MAINCONFIG = 20,
+ DNF_CONF_AUTOMATICCONFIG = 30,
+ DNF_CONF_REPOCONFIG = 40,
+ DNF_CONF_PLUGINDEFAULT = 50,
+ DNF_CONF_PLUGINCONFIG = 60,
+ DNF_CONF_DROPINCONFIG = 65,
+ DNF_CONF_COMMANDLINE = 70,
+ DNF_CONF_RUNTIME = 80
+};
+
+gchar *dnf_conf_main_get_option(const gchar *name, enum DnfConfPriority *priority, GError ** error);
+gboolean dnf_conf_main_set_option(const gchar *name, enum DnfConfPriority priority, const gchar *value, GError ** error);
+gboolean dnf_conf_add_setopt(const gchar *key, enum DnfConfPriority priority, const gchar *value, GError ** error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DNF_CONF_H_ */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ * Copyright © 2016 Igor Gnatenko <ignatenko@redhat.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-context
+ * @short_description: High level interface to libdnf.
+ * @include: libdnf.h
+ * @stability: Stable
+ *
+ * This object is a high level interface that does not allow the user
+ * to use objects from librepo, rpm or hawkey directly.
+ */
+
+#include "config.h"
+#include "conf/Const.hpp"
+#include "dnf-context.hpp"
+#include "libdnf/conf/ConfigParser.hpp"
+#include "conf/Option.hpp"
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "goal/Goal.hpp"
+
+#include <memory>
+#include <set>
+#include <vector>
+#include <unordered_set>
+#include <gio/gio.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmdb.h>
+#include <librepo/librepo.h>
+#ifdef RHSM_SUPPORT
+#include <rhsm/rhsm.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+#include <fnmatch.h>
+#include <unistd.h>
+
+#include "catch-error.hpp"
+#include "log.hpp"
+#include "tinyformat/tinyformat.hpp"
+#include "dnf-lock.h"
+#include "dnf-package.h"
+#include "dnf-repo-loader.h"
+#include "dnf-sack-private.hpp"
+#include "dnf-state.h"
+#include "dnf-transaction.h"
+#include "dnf-utils.h"
+#include "dnf-sack.h"
+#include "hy-query.h"
+#include "hy-query-private.hpp"
+#include "hy-subject.h"
+#include "hy-selector.h"
+#include "dnf-repo.hpp"
+#include "goal/Goal.hpp"
+#include "plugin/plugin-private.hpp"
+#include "utils/GLibLogger.hpp"
+#include "utils/os-release.hpp"
+
+
+#define MAX_NATIVE_ARCHES 12
+
+#define RELEASEVER_PROV "system-release(releasever)"
+
+/* data taken from https://github.com/rpm-software-management/dnf/blob/master/dnf/arch.py */
+static const struct {
+ const gchar *base;
+ const gchar *native[MAX_NATIVE_ARCHES];
+} arch_map[] = {
+ { "aarch64", { "aarch64", NULL } },
+ { "alpha", { "alpha", "alphaev4", "alphaev45", "alphaev5",
+ "alphaev56", "alphaev6", "alphaev67",
+ "alphaev68", "alphaev7", "alphapca56", NULL } },
+ { "arm", { "armv5tejl", "armv5tel", "armv5tl", "armv6l", "armv7l", "armv8l", NULL } },
+ { "armhfp", { "armv6hl", "armv7hl", "armv7hnl", "armv8hl", "armv8hnl", "armv8hcnl", NULL } },
+ { "i386", { "i386", "athlon", "geode", "i386",
+ "i486", "i586", "i686", NULL } },
+ { "ia64", { "ia64", NULL } },
+ { "mips", { "mips", NULL } },
+ { "mipsel", { "mipsel", NULL } },
+ { "mips64", { "mips64", NULL } },
+ { "mips64el", { "mips64el", NULL } },
+ { "noarch", { "noarch", NULL } },
+ { "ppc", { "ppc", NULL } },
+ { "ppc64", { "ppc64", "ppc64iseries", "ppc64p7",
+ "ppc64pseries", NULL } },
+ { "ppc64le", { "ppc64le", NULL } },
+ { "riscv32", { "riscv32", NULL } },
+ { "riscv64", { "riscv64", NULL } },
+ { "riscv128", { "riscv128", NULL } },
+ { "s390", { "s390", NULL } },
+ { "s390x", { "s390x", NULL } },
+ { "sh3", { "sh3", NULL } },
+ { "sh4", { "sh4", "sh4a", NULL } },
+ { "sparc", { "sparc", "sparc64", "sparc64v", "sparcv8",
+ "sparcv9", "sparcv9v", NULL } },
+ { "x86_64", { "x86_64", "amd64", "ia32e", NULL } },
+ { "loongarch64", { "loongarch64", NULL } },
+ { NULL, { NULL } }
+};
+
+const gchar *
+find_base_arch(const char *native) {
+ for (int i = 0; arch_map[i].base != NULL; i++) {
+ for (int j = 0; arch_map[i].native[j] != NULL; j++) {
+ if (g_strcmp0(arch_map[i].native[j], native) == 0) {
+ return arch_map[i].base;
+ }
+ }
+ }
+ return NULL;
+}
+
+typedef struct
+{
+ gchar **repos_dir;
+ gchar **vars_dir;
+ gchar **installonlypkgs;
+ gchar *base_arch;
+ gchar *release_ver;
+ gchar *platform_module;
+ gchar *cache_dir;
+ gchar *solv_dir;
+ gchar *vendor_cache_dir;
+ gchar *vendor_solv_dir;
+ gchar *lock_dir;
+ gchar *os_info;
+ gchar *arch_info;
+ gchar *install_root;
+ gchar *source_root;
+ gchar *rpm_verbosity;
+ gchar **native_arches{NULL};
+ gchar *http_proxy;
+ gchar *user_agent;
+ gchar *arch;
+ guint cache_age; /*seconds*/
+ gboolean cacheOnly{false};
+ gboolean check_disk_space;
+ gboolean check_transaction;
+ gboolean only_trusted;
+ gboolean *enable_filelists;
+ gboolean enrollment_valid;
+ gboolean write_history;
+ DnfLock *lock;
+ DnfTransaction *transaction;
+ GThread *transaction_thread;
+ GFileMonitor *monitor_rpmdb;
+ GHashTable *override_macros;
+
+ /* used to implement a transaction */
+ DnfRepoLoader *repo_loader;
+ GPtrArray *repos;
+ DnfState *state; /* used for setup() and run() */
+ HyGoal goal;
+ DnfSack *sack;
+ std::map<std::string, std::string> *vars;
+ bool varsCached;
+ libdnf::Plugins *plugins;
+} DnfContextPrivate;
+
+struct PluginHookContextInitData : public libdnf::PluginInitData {
+ PluginHookContextInitData(PluginMode mode, DnfContext * context)
+ : PluginInitData(mode), context(context) {}
+
+ DnfContext * context;
+};
+
+enum {
+ SIGNAL_INVALIDATE,
+ SIGNAL_LAST
+};
+
+static libdnf::GLibLogger glibLogger(G_LOG_DOMAIN);
+static std::string pluginsDir = DEFAULT_PLUGINS_DIRECTORY;
+static std::unique_ptr<std::string> configFilePath;
+static std::set<std::string> pluginsEnabled;
+static std::set<std::string> pluginsDisabled;
+static guint signals [SIGNAL_LAST] = { 0 };
+
+#ifdef RHSM_SUPPORT
+static bool disableInternalRhsmPlugin = false;
+#endif
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfContext, dnf_context, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfContextPrivate *>(dnf_context_get_instance_private (o)))
+
+/**
+ * dnf_context_rpmdb_changed_cb:
+ **/
+static void
+dnf_context_rpmdb_changed_cb(GFileMonitor *monitor_,
+ GFile *file, GFile *other_file,
+ GFileMonitorEvent event_type,
+ DnfContext *context)
+{
+ dnf_context_invalidate(context, "rpmdb changed");
+}
+
+/**
+ * dnf_context_finalize:
+ **/
+static void
+dnf_context_finalize(GObject *object)
+{
+ DnfContext *context = DNF_CONTEXT(object);
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ priv->plugins->free();
+ delete priv->plugins;
+ delete priv->vars;
+
+ g_strfreev(priv->repos_dir);
+ g_strfreev(priv->vars_dir);
+ g_strfreev(priv->installonlypkgs);
+ g_free(priv->base_arch);
+ g_free(priv->release_ver);
+ g_free(priv->platform_module);
+ g_free(priv->cache_dir);
+ g_free(priv->solv_dir);
+ g_free(priv->vendor_cache_dir);
+ g_free(priv->vendor_solv_dir);
+ g_free(priv->lock_dir);
+ g_free(priv->rpm_verbosity);
+ g_free(priv->install_root);
+ g_free(priv->source_root);
+ g_free(priv->os_info);
+ g_free(priv->arch_info);
+ g_free(priv->http_proxy);
+ g_free(priv->user_agent);
+ g_free(priv->arch);
+ g_free(priv->enable_filelists);
+ g_strfreev(priv->native_arches);
+ g_object_unref(priv->lock);
+ g_object_unref(priv->state);
+ g_hash_table_unref(priv->override_macros);
+
+ if (priv->transaction != NULL)
+ g_object_unref(priv->transaction);
+ if (priv->repo_loader != NULL)
+ g_object_unref(priv->repo_loader);
+ if (priv->repos != NULL)
+ g_ptr_array_unref(priv->repos);
+ if (priv->goal != NULL)
+ hy_goal_free(priv->goal);
+ if (priv->sack != NULL)
+ g_object_unref(priv->sack);
+ if (priv->monitor_rpmdb != NULL) {
+ g_signal_handlers_disconnect_by_func (priv->monitor_rpmdb,
+ (gpointer) dnf_context_rpmdb_changed_cb,
+ context);
+ g_object_unref(priv->monitor_rpmdb);
+ }
+
+ G_OBJECT_CLASS(dnf_context_parent_class)->finalize(object);
+}
+
+static void
+dnf_context_plugins_disable_enable(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ // apply pluginsDisabled and pluginsEnabled
+ std::set<std::string> patternDisableFound;
+ std::set<std::string> patternEnableFound;
+ for (size_t i = 0; i < priv->plugins->count(); ++i) {
+ auto pluginInfo = priv->plugins->getPluginInfo(i);
+ bool enabled = true;
+ for (const auto & patternSkip : pluginsDisabled) {
+ if (fnmatch(patternSkip.c_str(), pluginInfo->name, 0) == 0) {
+ enabled = false;
+ patternDisableFound.insert(patternSkip);
+ }
+ }
+ for (const auto & patternEnable : pluginsEnabled) {
+ if (fnmatch(patternEnable.c_str(), pluginInfo->name, 0) == 0) {
+ enabled = true;
+ patternEnableFound.insert(patternEnable);
+ }
+ }
+ if (!enabled) {
+ priv->plugins->enablePlugin(i, false);
+ }
+ }
+
+#ifdef RHSM_SUPPORT
+ // apply pluginsDisabled and pluginsEnabled to the internal RHSM plugin
+ const char * RhsmPluginName = "subscription-manager";
+ for (const auto & patternSkip : pluginsDisabled) {
+ if (fnmatch(patternSkip.c_str(), RhsmPluginName, 0) == 0) {
+ disableInternalRhsmPlugin = true;
+ patternDisableFound.insert(patternSkip);
+ }
+ }
+ for (const auto & patternEnable : pluginsEnabled) {
+ if (fnmatch(patternEnable.c_str(), RhsmPluginName, 0) == 0) {
+ disableInternalRhsmPlugin = false;
+ patternEnableFound.insert(patternEnable);
+ }
+ }
+#endif
+
+ // Log non matched disable patterns
+ std::string nonMatched;
+ for (const auto & pattern : pluginsDisabled) {
+ if (patternDisableFound.count(pattern) == 0) {
+ if (nonMatched.length() > 0) {
+ nonMatched += ", ";
+ }
+ nonMatched += pattern;
+ }
+ }
+ if (!nonMatched.empty()) {
+ g_warning("No matches found for the following disable plugin patterns: %s", nonMatched.c_str());
+ }
+
+ // Log non matched enable patterns
+ nonMatched.clear();
+ for (const auto & pattern : pluginsEnabled) {
+ if (patternEnableFound.count(pattern) == 0) {
+ if (nonMatched.length() > 0) {
+ nonMatched += ", ";
+ }
+ nonMatched += pattern;
+ }
+ }
+ if (!nonMatched.empty()) {
+ g_warning("No matches found for the following enable plugin patterns: %s", nonMatched.c_str());
+ }
+}
+
+/**
+ * dnf_context_init:
+ **/
+static void
+dnf_context_init(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ libdnf::Log::setLogger(&glibLogger);
+
+ priv->install_root = g_strdup("/");
+ priv->check_disk_space = TRUE;
+ priv->check_transaction = TRUE;
+ priv->write_history = TRUE;
+ priv->state = dnf_state_new();
+ priv->lock = dnf_lock_new();
+ priv->cache_age = 60 * 60 * 24 * 7; /* 1 week */
+ priv->override_macros = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+ priv->user_agent = g_strdup(libdnf::getUserAgent().c_str());
+
+ priv->vars = new std::map<std::string, std::string>;
+
+ priv->plugins = new libdnf::Plugins;
+
+ /* Initialize some state that used to happen in
+ * dnf_context_setup(), because callers like rpm-ostree want
+ * access to the basearch, but before installroot.
+ */
+ (void) dnf_context_globals_init(NULL);
+}
+
+/**
+ * dnf_context_globals_init:
+ * @error: a #GError or %NULL
+ *
+ * Sadly RPM has process global data. You should invoke
+ * this function early on in process startup. If not,
+ * it will be invoked for you.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_context_globals_init (GError **error) try
+{
+ static gsize initialized = 0;
+ gboolean ret = TRUE;
+
+ if (g_once_init_enter (&initialized)) {
+
+ /* librepo's globals */
+ lr_global_init();
+
+ /* librpm's globals */
+ if (rpmReadConfigFiles(NULL, NULL) != 0) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to read rpm config files");
+ ret = FALSE;
+ }
+
+ g_once_init_leave (&initialized, 1);
+ }
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_class_init:
+ **/
+static void
+dnf_context_class_init(DnfContextClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_context_finalize;
+
+ signals [SIGNAL_INVALIDATE] =
+ g_signal_new("invalidate",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfContextClass, invalidate),
+ NULL, NULL, g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+/**
+ * dnf_context_get_config_file_path:
+ *
+ * Gets the path to the global configuration file.
+ *
+ * Returns: Path to the global configuration file.
+ *
+ * Since: 0.42.0
+ **/
+const gchar *
+dnf_context_get_config_file_path()
+{
+ return configFilePath ? configFilePath->c_str() : libdnf::CONF_FILENAME;
+}
+
+/**
+ * dnf_context_is_set_config_file_path:
+ *
+ * Gets state of config_file_path.
+ *
+ * Returns: TRUE if config_file_path is set, FALSE if default is used.
+ *
+ * Since: 0.44.1
+ **/
+gboolean
+dnf_context_is_set_config_file_path()
+{
+ return configFilePath != nullptr;
+}
+
+/**
+ * dnf_context_get_repos_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets NULL terminated array of paths to the repositories directories.
+ *
+ * Returns: the NULL terminated array of paths, e.g. ["/etc/yum.repos.d", NULL]
+ *
+ * Since: 0.42.0
+ **/
+const gchar * const *
+dnf_context_get_repos_dir(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ if (!priv->repos_dir) {
+ auto & reposDir = libdnf::getGlobalMainConfig().reposdir().getValue();
+ priv->repos_dir = g_new(gchar*, reposDir.size() + 1);
+ for (size_t i = 0; i < reposDir.size(); ++i)
+ priv->repos_dir[i] = g_strdup(reposDir[i].c_str());
+ priv->repos_dir[reposDir.size()] = NULL;
+ }
+ return priv->repos_dir;
+}
+
+/**
+ * dnf_context_get_repo_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the repo directory.
+ *
+ * Returns: the path to repo directory, e.g. "/etc/yum.repos.d"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_repo_dir(DnfContext *context)
+{
+ static std::string reposDirStr;
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ dnf_context_get_repos_dir(context); // ensure retrieving of the value from the global config
+ reposDirStr = priv->repos_dir[0] ? priv->repos_dir[0] : "";
+ return reposDirStr.c_str();
+}
+
+/**
+ * dnf_context_get_vars_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the repo variables directories.
+ *
+ * Returns: the NULL terminated array of directories, e.g. ["/etc/dnf/vars", NULL]
+ *
+ * Since: 0.28.1
+ **/
+const gchar * const *
+dnf_context_get_vars_dir(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ if (!priv->vars_dir) {
+ auto & varsDir = libdnf::getGlobalMainConfig().varsdir().getValue();
+ priv->vars_dir = g_new(gchar*, varsDir.size() + 1);
+ for (size_t i = 0; i < varsDir.size(); ++i)
+ priv->vars_dir[i] = g_strdup(varsDir[i].c_str());
+ priv->vars_dir[varsDir.size()] = NULL;
+ }
+ return priv->vars_dir;
+}
+
+/**
+ * dnf_context_get_base_arch:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the context ID.
+ *
+ * Returns: the base architecture, e.g. "x86_64"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_base_arch(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ const char *value;
+
+ if (priv->base_arch)
+ return priv->base_arch;
+
+ /* get info from RPM */
+ rpmGetOsInfo(&value, NULL);
+ priv->os_info = g_strdup(value);
+ rpmGetArchInfo(&value, NULL);
+ priv->arch_info = g_strdup(value);
+ priv->base_arch = g_strdup(find_base_arch(value));
+
+ return priv->base_arch;
+}
+
+/**
+ * dnf_context_get_os_info:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the OS info.
+ *
+ * Returns: the OS info, e.g. "Linux"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_os_info(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->os_info;
+}
+
+/**
+ * dnf_context_get_arch_info:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the architecture info.
+ *
+ * Returns: the architecture info, e.g. "x86_64"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_arch_info(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->arch_info;
+}
+
+/**
+ * dnf_context_get_release_ver:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the release version.
+ *
+ * Returns: the version, e.g. "20"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_release_ver(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->release_ver;
+}
+
+/**
+ * dnf_context_get_platform_module:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the platform module seted in context (not autodetected)
+ *
+ * Returns: the name:stream, e.g. "platform:f28"
+ *
+ * Since: 0.16.1
+ **/
+const gchar *
+dnf_context_get_platform_module(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->platform_module;
+}
+
+/**
+ * dnf_context_get_cache_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the cache dir to use for metadata files.
+ *
+ * Returns: fully specified path
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_cache_dir(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->cache_dir;
+}
+
+/**
+ * dnf_context_get_arch:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the arch that was previously setted by dnf_context_set_arch().
+ *
+ * Returns: arch
+ * Since: 0.15.0
+ **/
+const gchar *
+dnf_context_get_arch(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->arch;
+}
+
+/**
+ * dnf_context_get_solv_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the solve cache directory.
+ *
+ * Returns: fully specified path
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_solv_dir(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->solv_dir;
+}
+
+/**
+ * dnf_context_get_lock_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the lock directory.
+ *
+ * Returns: fully specified path
+ *
+ * Since: 0.1.4
+ **/
+const gchar *
+dnf_context_get_lock_dir(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->lock_dir;
+}
+
+/**
+ * dnf_context_get_rpm_verbosity:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the RPM verbosity string.
+ *
+ * Returns: the verbosity string, e.g. "info"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_rpm_verbosity(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->rpm_verbosity;
+}
+
+/**
+ * dnf_context_get_install_root:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the install root, by default "/".
+ *
+ * Returns: the install root, e.g. "/tmp/snapshot"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_context_get_install_root(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->install_root;
+}
+
+/**
+ * dnf_context_get_source_root:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the source root, by default "/".
+ *
+ * Returns: the source root, e.g. "/tmp/my_os"
+ *
+ * Since: 0.7.0
+ **/
+const gchar *
+dnf_context_get_source_root(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->source_root != NULL ? priv->source_root : priv->install_root;
+}
+
+/**
+ * dnf_context_get_native_arches:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the native architectures, by default "noarch" and "i386".
+ *
+ * Returns: (transfer none): the native architectures
+ *
+ * Since: 0.1.0
+ **/
+const gchar **
+dnf_context_get_native_arches(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return(const gchar **) priv->native_arches;
+}
+
+/**
+ * dnf_context_get_repo_loader:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the repo loader used by the transaction.
+ *
+ * Returns: (transfer none): the repo loader
+ *
+ * Since: 0.7.0
+ **/
+DnfRepoLoader *
+dnf_context_get_repo_loader(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->repo_loader;
+}
+
+/**
+ * dnf_context_get_repos:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the repos used by the transaction.
+ *
+ * Returns: (transfer none) (element-type DnfRepo): the repo list
+ *
+ * Since: 0.1.0
+ **/
+GPtrArray *
+dnf_context_get_repos(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->repos;
+}
+
+/**
+ * dnf_context_ensure_transaction:
+ **/
+static void
+dnf_context_ensure_transaction(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create if not yet created */
+ if (priv->transaction == NULL) {
+ priv->transaction = dnf_transaction_new(context);
+ priv->transaction_thread = g_thread_self();
+ dnf_transaction_set_repos(priv->transaction, priv->repos);
+ return;
+ }
+
+ /* check the transaction is not being used from a different thread */
+ if (priv->transaction_thread != g_thread_self())
+ g_warning("transaction being re-used by a different thread!");
+}
+
+/**
+ * dnf_context_get_transaction:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the transaction used by the transaction.
+ *
+ * IMPORTANT: This function cannot be used if #DnfContext is being re-used by
+ * different threads, even if threads are run one at a time. If you're doing
+ * this, just create a DnfTransaction for each thread rather than using the
+ * context version.
+ *
+ * Returns: (transfer none): the DnfTransaction object
+ *
+ * Since: 0.1.0
+ **/
+DnfTransaction *
+dnf_context_get_transaction(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ /* ensure transaction exists */
+ dnf_context_ensure_transaction(context);
+ return priv->transaction;
+}
+
+/**
+ * dnf_context_get_sack:(skip)
+ * @context: a #DnfContext instance.
+ *
+ * Returns: (transfer none): the DnfSack object
+ *
+ * Since: 0.1.0
+ **/
+DnfSack *
+dnf_context_get_sack(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->sack;
+}
+
+/**
+ * dnf_context_get_goal:(skip)
+ * @context: a #DnfContext instance.
+ *
+ * Returns: (transfer none): the HyGoal object
+ *
+ * Since: 0.1.0
+ **/
+HyGoal
+dnf_context_get_goal(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->goal;
+}
+
+/**
+ * dnf_context_get_state:
+ * @context: a #DnfContext instance.
+ *
+ * Returns: (transfer none): the DnfState object
+ *
+ * Since: 0.1.2
+ **/
+DnfState*
+dnf_context_get_state(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->state;
+}
+
+/**
+ * dnf_context_get_user_agent:
+ * @context: a #DnfContext instance.
+ *
+ * Returns: (transfer none): the user agent
+ **/
+const gchar *
+dnf_context_get_user_agent (DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->user_agent;
+}
+
+/**
+ * dnf_context_get_cache_only:
+ * @context: a #DnfContext instance.
+ *
+ * Gets cache only mode status.
+ *
+ * Returns: %TRUE if cache only mode is enabled
+ *
+ * Since: 0.21.0
+ **/
+gboolean
+dnf_context_get_cache_only(DnfContext * context)
+{
+ auto priv = GET_PRIVATE(context);
+ return priv->cacheOnly;
+}
+
+/**
+ * dnf_context_get_best:
+ *
+ * Gets best global configuration value.
+ *
+ * Returns: %TRUE if best mode is enabled
+ *
+ * Since: 0.37.0
+ **/
+gboolean
+dnf_context_get_best()
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.best().getValue();
+}
+
+/**
+ * dnf_context_get_install_weak_deps:
+ *
+ * Gets install_weak_deps global configuration value.
+ *
+ * Returns: %TRUE if installation of weak dependencies is allowed
+ *
+ * Since: 0.40.0
+ */
+gboolean
+dnf_context_get_install_weak_deps()
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.install_weak_deps().getValue();
+}
+
+/**
+ * dnf_context_get_allow_vendor_change:
+ *
+ * Gets allow_vendor_change global configuration value.
+ *
+ * Returns: %TRUE if changing vendors in a transaction is allowed
+ *
+ * Since: 0.55.2
+ */
+gboolean
+dnf_context_get_allow_vendor_change()
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.allow_vendor_change().getValue();
+}
+
+/**
+ * dnf_context_get_check_disk_space:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the diskspace check value.
+ *
+ * Returns: %TRUE if diskspace should be checked before the transaction
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_get_check_disk_space(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->check_disk_space;
+}
+
+/**
+ * dnf_context_get_check_transaction:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the test transaction value. A test transaction shouldn't be required
+ * with hawkey and it takes extra time to complete, but bad things happen
+ * if hawkey ever gets this wrong.
+ *
+ * Returns: %TRUE if a test transaction should be done
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_get_check_transaction(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->check_transaction;
+}
+
+/**
+ * dnf_context_get_keep_cache:
+ * @context: a #DnfContext instance.
+ *
+ * Gets if the downloaded packages are kept.
+ *
+ * Returns: %TRUE if the packages will not be deleted
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_get_keep_cache(DnfContext *context)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.keepcache().getValue();
+}
+
+/**
+ * dnf_context_get_only_trusted:
+ * @context: a #DnfContext instance.
+ *
+ * Gets if only trusted packages can be installed.
+ *
+ * Returns: %TRUE if only trusted packages are allowed
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_get_only_trusted(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->only_trusted;
+}
+
+/**
+ * dnf_context_get_zchunk
+ * @context: a #DnfContext instance is not used. It is global option.
+ *
+ * Gets whether zchunk is enabled
+ *
+ * Returns: %TRUE if zchunk is enabled
+ *
+ * Since: 0.21.0
+ **/
+gboolean
+dnf_context_get_zchunk(DnfContext *context)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.zchunk().getValue();
+}
+
+/**
+ * dnf_context_get_write_history
+ * @context: a #DnfContext instance.
+ *
+ * Gets whether writing to history database is enabled.
+ *
+ * Returns: %TRUE if writing to history database is enabled
+ *
+ * Since: 0.27.2
+ **/
+gboolean
+dnf_context_get_write_history(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->write_history;
+}
+
+/**
+ * dnf_context_get_enable_filelists:
+ * @context: a #DnfContext instance.
+ *
+ * Returns: %TRUE if filelists are enabled
+ *
+ * Since: 0.13.0
+ */
+gboolean
+dnf_context_get_enable_filelists (DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ if (priv->enable_filelists == NULL) {
+ priv->enable_filelists = g_new(gboolean, 1);
+
+ auto & optional_metadata_types = libdnf::getGlobalMainConfig(false).optional_metadata_types().getValue();
+ *priv->enable_filelists = std::find(optional_metadata_types.begin(),
+ optional_metadata_types.end(),
+ "filelists") != optional_metadata_types.end();
+ }
+ return *priv->enable_filelists;
+}
+
+/**
+ * dnf_context_get_cache_age:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the maximum cache age.
+ *
+ * Returns: cache age in seconds
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_context_get_cache_age(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->cache_age;
+}
+
+/**
+ * dnf_context_get_installonly_pkgs:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the packages that are allowed to be installed more than once.
+ *
+ * The return value is valid until the value of the global configuration "installonlypkgs" changes.
+ * E.g. using dnf_conf_main_set_option() or dnf_conf_add_setopt().
+ *
+ * Returns: (transfer none): array of package names
+ */
+const gchar **
+dnf_context_get_installonly_pkgs(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ auto & packages = mainConf.installonlypkgs().getValue();
+
+ // If "installonlypkgs" is not initialized (first run), set "differs" to true.
+ bool differs = !priv->installonlypkgs;
+
+ // Test if they are not different.
+ if (!differs) {
+ size_t i = 0;
+ while (i < packages.size()) {
+ if (!priv->installonlypkgs[i] || packages[i].compare(priv->installonlypkgs[i]) != 0) {
+ differs = true;
+ break;
+ }
+ ++i;
+ }
+ if (priv->installonlypkgs[i]) {
+ differs = true;
+ }
+ }
+
+ // Re-initialize "installonlypkgs" only if it differs from the values in mainConf.
+ if (differs) {
+ g_strfreev(priv->installonlypkgs);
+ priv->installonlypkgs = g_new0(gchar*, packages.size() + 1);
+
+ for (size_t i = 0; i < packages.size(); ++i) {
+ priv->installonlypkgs[i] = g_strdup(packages[i].c_str());
+ }
+ }
+
+ return const_cast<const gchar **>(priv->installonlypkgs);
+}
+
+/**
+ * dnf_context_get_installonly_limit:
+ * @context: a #DnfContext instance.
+ *
+ * Gets the maximum number of packages for installonly packages
+ *
+ * Returns: integer value
+ */
+guint
+dnf_context_get_installonly_limit(DnfContext *context)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return mainConf.installonly_limit().getValue();
+}
+
+/**
+ * dnf_context_set_config_file_path:
+ * @config_file_path: the path, e.g. "/etc/dnf/dnf.conf"
+ *
+ * Sets the path to the global configuration file. The empty string means no read configuration
+ * file. NULL resets the path to the default value. Must be used before
+ * dnf_context_get_*, and dnf_context_setup functions are called.
+ *
+ * Since: 0.42.0
+ **/
+void
+dnf_context_set_config_file_path(const gchar * config_file_path)
+{
+ if (config_file_path) {
+ configFilePath.reset(new std::string(config_file_path));
+ } else {
+ configFilePath.reset();
+ }
+}
+
+/**
+ * dnf_context_set_repos_dir:
+ * @context: a #DnfContext instance.
+ * @repos_dir: the NULL terminated array of paths, e.g. ["/etc/yum.repos.d", NULL]
+ *
+ * Sets the repositories directories.
+ *
+ * Since: 0.42.0
+ **/
+void
+dnf_context_set_repos_dir(DnfContext *context, const gchar * const *repos_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_strfreev(priv->repos_dir);
+ if (repos_dir) {
+ guint len = 1;
+ for (auto iter = repos_dir; *iter; ++iter) {
+ ++len;
+ }
+ priv->repos_dir = g_new(gchar*, len);
+ for (guint i = 0; i < len; ++i) {
+ priv->repos_dir[i] = g_strdup(repos_dir[i]);
+ }
+ } else {
+ priv->repos_dir = NULL;
+ }
+}
+
+/**
+ * dnf_context_set_repo_dir:
+ * @context: a #DnfContext instance.
+ * @repo_dir: the repodir, e.g. "/etc/yum.repos.d"
+ *
+ * Sets the repo directory.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_repo_dir(DnfContext *context, const gchar *repo_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_strfreev(priv->repos_dir);
+ if (repo_dir) {
+ priv->repos_dir = g_new0(gchar*, 2);
+ priv->repos_dir[0] = g_strdup(repo_dir);
+ } else {
+ priv->repos_dir = NULL;
+ }
+}
+
+/**
+ * dnf_context_set_vars_dir:
+ * @context: a #DnfContext instance.
+ * @vars_dir: the vars directories, e.g. ["/etc/dnf/vars"]
+ *
+ * Sets the repo variables directory.
+ *
+ * Since: 0.28.1
+ **/
+void
+dnf_context_set_vars_dir(DnfContext *context, const gchar * const *vars_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_strfreev(priv->vars_dir);
+ priv->vars_dir = g_strdupv(const_cast<gchar **>(vars_dir));
+ priv->varsCached = false;
+}
+
+/**
+ * dnf_context_set_release_ver:
+ * @context: a #DnfContext instance.
+ * @release_ver: the release version, e.g. "20"
+ *
+ * Sets the release version.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_release_ver(DnfContext *context, const gchar *release_ver)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->release_ver);
+ priv->release_ver = g_strdup(release_ver);
+}
+
+/**
+ * dnf_context_set_platform_module:
+ * @context: a #DnfContext instance.
+ * @release_ver: the platform name:stream, e.g. "platform:28"
+ *
+ * Sets the platform module. If value is set it disable autodetection of platform module.
+ *
+ * Since: 0.16.1
+ **/
+void
+dnf_context_set_platform_module(DnfContext *context, const gchar *platform_module)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->platform_module);
+ priv->platform_module = g_strdup(platform_module);
+}
+
+/**
+ * dnf_context_set_cache_dir:
+ * @context: a #DnfContext instance.
+ * @cache_dir: the cachedir, e.g. "/var/cache/PackageKit"
+ *
+ * Sets the cache directory.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_cache_dir(DnfContext *context, const gchar *cache_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->cache_dir);
+ priv->cache_dir = g_strdup(cache_dir);
+}
+
+/**
+ * dnf_context_set_arch:
+ * @context: a #DnfContext instance.
+ * @base_arch: the base_arch, e.g. "x86_64"
+ *
+ * Sets the base arch of sack.
+ *
+ * Since: 0.15.0
+ **/
+void
+dnf_context_set_arch(DnfContext *context, const gchar *arch)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->arch);
+ priv->arch = g_strdup(arch);
+}
+
+/**
+ * dnf_context_set_solv_dir:
+ * @context: a #DnfContext instance.
+ * @solv_dir: the solve cache, e.g. "/var/cache/PackageKit/hawkey"
+ *
+ * Sets the solve cache directory.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_solv_dir(DnfContext *context, const gchar *solv_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->solv_dir);
+ priv->solv_dir = g_strdup(solv_dir);
+}
+
+/**
+ * dnf_context_set_vendor_cache_dir:
+ * @context: a #DnfContext instance.
+ * @vendor_cache_dir: the cachedir, e.g. "/usr/share/PackageKit/metadata"
+ *
+ * Sets the vendor cache directory.
+ *
+ * Since: 0.1.6
+ **/
+void
+dnf_context_set_vendor_cache_dir(DnfContext *context, const gchar *vendor_cache_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->vendor_cache_dir);
+ priv->vendor_cache_dir = g_strdup(vendor_cache_dir);
+}
+
+/**
+ * dnf_context_set_vendor_solv_dir:
+ * @context: a #DnfContext instance.
+ * @vendor_solv_dir: the solve cache, e.g. "/usr/share/PackageKit/hawkey"
+ *
+ * Sets the vendor solve cache directory.
+ *
+ * Since: 0.1.6
+ **/
+void
+dnf_context_set_vendor_solv_dir(DnfContext *context, const gchar *vendor_solv_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->vendor_solv_dir);
+ priv->vendor_solv_dir = g_strdup(vendor_solv_dir);
+}
+
+/**
+ * dnf_context_set_lock_dir:
+ * @context: a #DnfContext instance.
+ * @lock_dir: the solve cache, e.g. "/var/run"
+ *
+ * Sets the lock directory.
+ *
+ * Since: 0.1.4
+ **/
+void
+dnf_context_set_lock_dir(DnfContext *context, const gchar *lock_dir)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->lock_dir);
+ priv->lock_dir = g_strdup(lock_dir);
+}
+
+/**
+ * dnf_context_set_rpm_verbosity:
+ * @context: a #DnfContext instance.
+ * @rpm_verbosity: the verbosity string, e.g. "info"
+ *
+ * Sets the RPM verbosity string.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_rpm_verbosity(DnfContext *context, const gchar *rpm_verbosity)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->rpm_verbosity);
+ priv->rpm_verbosity = g_strdup(rpm_verbosity);
+}
+
+/**
+ * dnf_context_set_install_root:
+ * @context: a #DnfContext instance.
+ * @install_root: the install root, e.g. "/"
+ *
+ * Sets the install root to use for installing and removal.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_install_root(DnfContext *context, const gchar *install_root)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->install_root);
+ priv->install_root = g_strdup(install_root);
+}
+
+/**
+ * dnf_context_set_source_root:
+ * @context: a #DnfContext instance.
+ * @source_root: the source root, e.g. "/"
+ *
+ * Sets the source root to use for retrieving system information.
+ *
+ * Since: 0.7.0
+ **/
+void
+dnf_context_set_source_root(DnfContext *context, const gchar *source_root)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->source_root);
+ priv->source_root = g_strdup(source_root);
+}
+
+/**
+ * dnf_context_set_best:
+ * @gboolean: a value for best configuration
+ *
+ * Sets best global configuration value.
+ *
+ * Since: 0.37.0
+ **/
+void
+dnf_context_set_best(gboolean best)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.best().set(libdnf::Option::Priority::RUNTIME, best);
+}
+
+/**
+ * dnf_context_set_install_weak_deps:
+ *
+ * Sets install_weak_deps global configuration value.
+ *
+ * Since: 0.40.0
+ */
+void
+dnf_context_set_install_weak_deps(gboolean enabled)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.install_weak_deps().set(libdnf::Option::Priority::RUNTIME, enabled);
+}
+
+/**
+ * dnf_context_set_allow_vendor_change:
+ *
+ * Sets allow_vendor_change global configuration value.
+ *
+ * Since: 0.55.2
+ */
+void
+dnf_context_set_allow_vendor_change(gboolean vendorchange)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.allow_vendor_change().set(libdnf::Option::Priority::RUNTIME, vendorchange);
+}
+
+/**
+ * dnf_context_set_cache_only:
+ * @context: a #DnfContext instance.
+ * @cache_only: %TRUE to use only metadata from cache
+ *
+ * Enables or disables cache only mode.
+ *
+ * Since: 0.21.0
+ **/
+void
+dnf_context_set_cache_only(DnfContext * context, gboolean cache_only)
+{
+ auto priv = GET_PRIVATE(context);
+ priv->cacheOnly = cache_only;
+}
+
+
+/**
+ * dnf_context_set_check_disk_space:
+ * @context: a #DnfContext instance.
+ * @check_disk_space: %TRUE to check for diskspace
+ *
+ * Enables or disables the diskspace check.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_check_disk_space(DnfContext *context, gboolean check_disk_space)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ priv->check_disk_space = check_disk_space;
+}
+
+/**
+ * dnf_context_set_check_transaction:
+ * @context: a #DnfContext instance.
+ * @check_transaction: %TRUE to do a test transaction
+ *
+ * Enables or disables the test transaction.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_check_transaction(DnfContext *context, gboolean check_transaction)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ priv->check_transaction = check_transaction;
+}
+
+/**
+ * dnf_context_set_keep_cache:
+ * @context: a #DnfContext instance.
+ * @keep_cache: %TRUE keep the packages after installing or updating
+ *
+ * Enables or disables the automatic package deleting functionality.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_keep_cache(DnfContext *context, gboolean keep_cache)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.keepcache().set(libdnf::Option::Priority::RUNTIME, keep_cache);
+}
+
+/**
+ * dnf_context_set_enable_filelists:
+ * @context: a #DnfContext instance.
+ * @enable_filelists: %TRUE to download and parse filelist metadata
+ *
+ * Enables or disables download and parsing of filelists.
+ *
+ * Since: 0.13.0
+ **/
+void
+dnf_context_set_enable_filelists (DnfContext *context,
+ gboolean enable_filelists)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ if (priv->enable_filelists == NULL) {
+ priv->enable_filelists = g_new(gboolean, 1);
+ }
+ *priv->enable_filelists = enable_filelists;
+}
+
+/**
+ * dnf_context_set_only_trusted:
+ * @context: a #DnfContext instance.
+ * @only_trusted: %TRUE keep the packages after installing or updating
+ *
+ * Enables or disables the requirement of trusted packages.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_only_trusted(DnfContext *context, gboolean only_trusted)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ priv->only_trusted = only_trusted;
+}
+
+/**
+ * dnf_context_set_zchunk:
+ * @context: a #DnfContext instance is not used. It is global option.
+ * @only_trusted: %TRUE use zchunk metadata if available
+ *
+ * Enables or disables the use of zchunk metadata if available.
+ *
+ * Since: 0.21.0
+ **/
+void
+dnf_context_set_zchunk(DnfContext *context, gboolean zchunk)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.zchunk().set(libdnf::Option::Priority::RUNTIME, zchunk);
+}
+
+/**
+ * dnf_context_set_write_history:
+ * @context: a #DnfContext instance.
+ * @value: %TRUE write history database
+ *
+ * Enables or disables writing to history database.
+ *
+ * Since: 0.27.2
+ **/
+void
+dnf_context_set_write_history(DnfContext *context, gboolean value)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ priv->write_history = value;
+}
+
+/**
+ * dnf_context_set_cache_age:
+ * @context: a #DnfContext instance.
+ * @cache_age: Maximum cache age in seconds
+ *
+ * Sets the maximum cache age.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_set_cache_age(DnfContext *context, guint cache_age)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ priv->cache_age = cache_age;
+}
+
+/**
+ * dnf_context_set_os_release:
+ **/
+static gboolean
+dnf_context_set_os_release(DnfContext *context, GError **error) try
+{
+ const char *source_root = dnf_context_get_source_root (context);
+
+ gboolean found_in_rpmdb = FALSE;
+ rpmts ts = rpmtsCreate ();
+ rpmtsSetRootDir (ts, source_root);
+ rpmdbMatchIterator mi = rpmtsInitIterator (ts, RPMTAG_PROVIDENAME, RELEASEVER_PROV, 0);
+ Header hdr;
+ while ((hdr = rpmdbNextIterator (mi)) != NULL) {
+ const char *v = headerGetString (hdr, RPMTAG_VERSION);
+ rpmds ds = rpmdsNew (hdr, RPMTAG_PROVIDENAME, 0);
+ while (rpmdsNext (ds) >= 0) {
+ if (strcmp (rpmdsN (ds), RELEASEVER_PROV) == 0 && rpmdsFlags (ds) == RPMSENSE_EQUAL)
+ v = rpmdsEVR (ds);
+ }
+ found_in_rpmdb = TRUE;
+ dnf_context_set_release_ver (context, v);
+ rpmdsFree (ds);
+ break;
+ }
+ rpmdbFreeIterator (mi);
+ rpmtsFree (ts);
+ if (found_in_rpmdb)
+ return TRUE;
+
+ g_autofree gchar *contents = NULL;
+ g_autofree gchar *maybe_quoted_version = NULL;
+ g_autofree gchar *version = NULL;
+ g_autofree gchar *os_release = NULL;
+ g_autoptr(GString) str = NULL;
+ g_autoptr(GKeyFile) key_file = NULL;
+
+ os_release = g_build_filename(source_root, "etc/os-release", NULL);
+ if (!dnf_get_file_contents_allow_noent(os_release, &contents, NULL, error))
+ return FALSE;
+
+ if (contents == NULL) {
+ g_free(os_release);
+ /* For rpm-ostree use on systems that haven't adapted to usr/lib/os-release yet,
+ * e.g. CentOS 7 Core AH */
+ os_release = g_build_filename(source_root, "usr/etc/os-release", NULL);
+ if (!dnf_get_file_contents_allow_noent(os_release, &contents, NULL, error))
+ return FALSE;
+ }
+
+ if (contents == NULL) {
+ g_free (os_release);
+ os_release = g_build_filename(source_root, "usr/lib/os-release", NULL);
+ if (!dnf_get_file_contents_allow_noent(os_release, &contents, NULL, error))
+ return FALSE;
+ }
+
+ if (contents == NULL) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_NOT_FOUND,
+ "Could not find os-release in etc/, usr/etc, or usr/lib "
+ "under source root '%s'", source_root);
+ return FALSE;
+ }
+
+ str = g_string_new(contents);
+
+ /* make a valid GKeyFile from the .ini data by prepending a header */
+ g_string_prepend(str, "[os-release]\n");
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_data(key_file,
+ str->str, -1,
+ G_KEY_FILE_NONE,
+ error))
+ return FALSE;
+
+ /* get keys */
+ maybe_quoted_version = g_key_file_get_string(key_file,
+ "os-release",
+ "VERSION_ID",
+ error);
+ if (maybe_quoted_version == NULL)
+ return FALSE;
+ version = g_shell_unquote(maybe_quoted_version, error);
+ if (!version)
+ return FALSE;
+ dnf_context_set_release_ver(context, version);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_set_user_agent:
+ * @context: Context
+ * @user_agent: User-Agent string for HTTP requests
+ **/
+void
+dnf_context_set_user_agent (DnfContext *context,
+ const gchar *user_agent)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free (priv->user_agent);
+ priv->user_agent = g_strdup (user_agent);
+}
+
+/* A heuristic; check whether /usr exists in the install root */
+static gboolean
+have_existing_install(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_autofree gchar *usr_path = g_build_filename(priv->install_root, "usr", NULL);
+ return g_file_test(usr_path, G_FILE_TEST_IS_DIR);
+}
+
+/**
+ * dnf_context_setup_sack:(skip)
+ * @context: a #DnfContext instance.
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ *
+ * Sets up the internal sack ready for use -- note, this is called automatically
+ * when you use dnf_context_install(), dnf_context_remove() or
+ * dnf_context_update(), although you may want to call this manually to control
+ * the DnfState children with correct percentage completion.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.3
+ **/
+gboolean
+dnf_context_setup_sack(DnfContext *context, DnfState *state, GError **error) try
+{
+ return dnf_context_setup_sack_with_flags(context, state,
+ DNF_CONTEXT_SETUP_SACK_FLAG_NONE, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_setup_sack_with_flags:(skip)
+ * @context: a #DnfContext instance.
+ * @state: A #DnfState
+ * @flags: A #DnfContextSetupSackFlags
+ * @error: A #GError or %NULL
+ *
+ * Sets up the internal sack ready for use. This provides the same functionality as
+ * dnf_context_setup_sack but allows finer control on its behaviour.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.13.0
+ **/
+gboolean
+dnf_context_setup_sack_with_flags(DnfContext *context,
+ DnfState *state,
+ DnfContextSetupSackFlags flags,
+ GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ gboolean ret;
+ g_autofree gchar *solv_dir_real = nullptr;
+ gboolean vendorchange;
+
+ /* create empty sack */
+ solv_dir_real = dnf_realpath(priv->solv_dir);
+ vendorchange = dnf_context_get_allow_vendor_change();
+ priv->sack = dnf_sack_new();
+ dnf_sack_set_cachedir(priv->sack, solv_dir_real);
+ dnf_sack_set_rootdir(priv->sack, priv->install_root);
+ dnf_sack_set_allow_vendor_change(priv->sack, vendorchange);
+ if (priv->arch) {
+ if(!dnf_sack_set_arch(priv->sack, priv->arch, error)) {
+ return FALSE;
+ }
+ }
+ if (!dnf_sack_setup(priv->sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, error))
+ return FALSE;
+ dnf_sack_set_installonly(priv->sack, dnf_context_get_installonly_pkgs(context));
+ dnf_sack_set_installonly_limit(priv->sack, dnf_context_get_installonly_limit(context));
+
+ /* add installed packages */
+ const gboolean skip_rpmdb = ((flags & DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_RPMDB) > 0);
+ if (!skip_rpmdb && have_existing_install(context)) {
+ if (!dnf_sack_load_system_repo(priv->sack,
+ nullptr,
+ DNF_SACK_LOAD_FLAG_NONE,
+ error))
+ return FALSE;
+ }
+
+ DnfSackAddFlags add_flags = DNF_SACK_ADD_FLAG_NONE;
+ if ((flags & DNF_CONTEXT_SETUP_SACK_FLAG_LOAD_UPDATEINFO) > 0)
+ add_flags = static_cast<DnfSackAddFlags>(add_flags | DNF_SACK_ADD_FLAG_UPDATEINFO);
+ if (dnf_context_get_enable_filelists(context) && !((flags & DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_FILELISTS) > 0))
+ add_flags = static_cast<DnfSackAddFlags>(add_flags | DNF_SACK_ADD_FLAG_FILELISTS);
+
+ /* add remote */
+ ret = dnf_sack_add_repos(priv->sack,
+ priv->repos,
+ priv->cache_age,
+ add_flags,
+ state,
+ error);
+ if (!ret)
+ return FALSE;
+
+ DnfSack *sack = priv->sack;
+ if (sack != nullptr) {
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ try {
+ dnf_sack_filter_modules_v2(sack, nullptr, hotfixRepos.data(), priv->install_root,
+ priv->platform_module, false, false, false);
+ } catch (libdnf::ModulePackageContainer::ConflictException & exception) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FAILED, "%s", exception.what());
+ return FALSE;
+ }
+ }
+
+ /* create goal */
+ if (priv->goal != nullptr)
+ hy_goal_free(priv->goal);
+ priv->goal = hy_goal_create(priv->sack);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_ensure_exists:
+ **/
+static gboolean
+dnf_context_ensure_exists(const gchar *directory, GError **error) try
+{
+ if (g_file_test(directory, G_FILE_TEST_EXISTS))
+ return TRUE;
+ if (g_mkdir_with_parents(directory, 0755) != 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Failed to create: %s", directory);
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_utils_copy_files:
+ */
+static gboolean
+dnf_utils_copy_files(const gchar *src, const gchar *dest, GError **error) try
+{
+ const gchar *tmp;
+ gint rc;
+ g_autoptr(GDir) dir = NULL;
+
+ /* create destination directory */
+ rc = g_mkdir_with_parents(dest, 0755);
+ if (rc < 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FAILED,
+ "failed to create %s", dest);
+ return FALSE;
+ }
+
+ /* copy files */
+ dir = g_dir_open(src, 0, error);
+ if (dir == NULL)
+ return FALSE;
+ while ((tmp = g_dir_read_name(dir)) != NULL) {
+ g_autofree gchar *path_src = NULL;
+ g_autofree gchar *path_dest = NULL;
+ path_src = g_build_filename(src, tmp, NULL);
+ path_dest = g_build_filename(dest, tmp, NULL);
+ if (g_file_test(path_src, G_FILE_TEST_IS_DIR)) {
+ if (!dnf_utils_copy_files(path_src, path_dest, error))
+ return FALSE;
+ } else {
+ g_autoptr(GFile) file_src = NULL;
+ g_autoptr(GFile) file_dest = NULL;
+ file_src = g_file_new_for_path(path_src);
+ file_dest = g_file_new_for_path(path_dest);
+ if (!g_file_copy(file_src, file_dest,
+ G_FILE_COPY_NONE,
+ NULL, NULL, NULL,
+ error))
+ return FALSE;
+ }
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_copy_vendor_cache:
+ *
+ * The vendor cache is typically structured like this:
+ * /usr/share/PackageKit/metadata/fedora/repodata/primary.xml.gz
+ * /usr/share/PackageKit/metadata/updates/repodata/primary.xml.gz
+ **/
+static gboolean
+dnf_context_copy_vendor_cache(DnfContext *context, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ DnfRepo *repo;
+ const gchar *id;
+ guint i;
+
+ /* not set, or does not exists */
+ if (priv->vendor_cache_dir == NULL)
+ return TRUE;
+ if (!g_file_test(priv->vendor_cache_dir, G_FILE_TEST_EXISTS))
+ return TRUE;
+
+ /* test each enabled repo in turn */
+ for (i = 0; i < priv->repos->len; i++) {
+ g_autofree gchar *path = NULL;
+ g_autofree gchar *path_vendor = NULL;
+ repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
+ continue;
+
+ /* does the repo already exist */
+ id = dnf_repo_get_id(repo);
+ path = g_build_filename(priv->cache_dir, id, NULL);
+ if (g_file_test(path, G_FILE_TEST_EXISTS))
+ continue;
+
+ /* copy the files */
+ path_vendor = g_build_filename(priv->vendor_cache_dir, id, NULL);
+ if (!g_file_test(path_vendor, G_FILE_TEST_EXISTS))
+ continue;
+ g_debug("copying files from %s to %s", path_vendor, path);
+ if (!dnf_utils_copy_files(path_vendor, path, error))
+ return FALSE;
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_copy_vendor_solv:
+ *
+ * The solv cache is typically structured like this:
+ * /usr/share/PackageKit/hawkey/@System.solv
+ * /usr/share/PackageKit/hawkey/fedora-filenames.solvx
+ **/
+static gboolean
+dnf_context_copy_vendor_solv(DnfContext *context, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_autofree gchar *system_db = NULL;
+
+ /* not set, or does not exists */
+ if (priv->vendor_solv_dir == NULL)
+ return TRUE;
+ if (!g_file_test(priv->vendor_solv_dir, G_FILE_TEST_EXISTS))
+ return TRUE;
+
+ /* already exists */
+ system_db = g_build_filename(priv->solv_dir, "@System.solv", NULL);
+ if (g_file_test(system_db, G_FILE_TEST_EXISTS))
+ return TRUE;
+
+ /* copy all the files */
+ g_debug("copying files from %s to %s", priv->vendor_solv_dir, priv->solv_dir);
+ if (!dnf_utils_copy_files(priv->vendor_solv_dir, priv->solv_dir, error))
+ return FALSE;
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_set_rpm_macro:
+ * @context: a #DnfContext instance.
+ * @key: Variable name
+ * @value: Variable value
+ *
+ * Override an RPM macro definition. This is useful for
+ * "_install_langs" and other macros that control aspects of the
+ * installation.
+ *
+ * Since: 0.1.9
+ **/
+void
+dnf_context_set_rpm_macro(DnfContext *context,
+ const gchar *key,
+ const gchar *value)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_hash_table_replace(priv->override_macros, g_strdup(key), g_strdup(value));
+}
+
+
+/**
+ * dnf_context_get_http_proxy:
+ * @context: a #DnfContext instance.
+ *
+ * Returns: the HTTP proxy; none is configured by default.
+ *
+ * Since: 0.1.9
+ **/
+const gchar *
+dnf_context_get_http_proxy(DnfContext *context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->http_proxy;
+}
+
+/**
+ * dnf_context_set_http_proxy:
+ * @context: a #DnfContext instance.
+ * @proxyurl: Proxy URL
+ *
+ * Set the HTTP proxy used by default. Per-repo configuration will
+ * override.
+ *
+ * Since: 0.1.9
+ **/
+void
+dnf_context_set_http_proxy(DnfContext *context, const gchar *proxyurl)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_free(priv->http_proxy);
+ priv->http_proxy = g_strdup(proxyurl);
+}
+
+/**
+ * dnf_context_setup_enrollments:
+ * @context: a #DnfContext instance.
+ * @error: A #GError or %NULL
+ *
+ * Resyncs the enrollment with the vendor system. This may change the contents
+ * of files in repos.d according to subscription levels.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.2.1
+ **/
+gboolean
+dnf_context_setup_enrollments(DnfContext *context, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* no need to refresh */
+ if (priv->enrollment_valid)
+ return TRUE;
+
+ /* Let's assume that alternative installation roots don't
+ * require entitlement. We only want to do system things if
+ * we're actually affecting the system. A more accurate test
+ * here would be checking that we're using /etc/yum.repos.d or
+ * so, but that can come later.
+ */
+ if (g_strcmp0(priv->install_root, "/") != 0)
+ return TRUE;
+
+ /* Also, all of the subman stuff only works as root, if we're not
+ * root, assume we're running in the test suite, or we're part of
+ * e.g. rpm-ostree which is trying to run totally as non-root.
+ */
+ if (getuid () != 0)
+ return TRUE;
+
+#ifdef RHSM_SUPPORT
+ /* Do not use the "hardcoded plugin" if this plugin or all plugins are disabled. */
+ if (disableInternalRhsmPlugin || !libdnf::getGlobalMainConfig().plugins().getValue()) {
+ return TRUE;
+ }
+
+ /* If /var/lib/rhsm exists, then we can assume that
+ * subscription-manager is installed, and thus don't need to
+ * manage redhat.repo via librhsm.
+ */
+ if (access("/var/lib/rhsm", F_OK) == 0) {
+ return TRUE;
+ }
+ g_autoptr(RHSMContext) rhsm_ctx = rhsm_context_new ();
+ auto repo_dir = dnf_context_get_repo_dir(context);
+ g_autofree gchar *repofname = g_build_filename (repo_dir,
+ "redhat.repo",
+ NULL);
+ g_autoptr(GKeyFile) repofile = rhsm_utils_yum_repo_from_context (rhsm_ctx);
+
+ bool sameContent = false;
+ do {
+ int fd;
+ if ((fd = open(repofname, O_RDONLY)) == -1)
+ break;
+ gsize length;
+ g_autofree gchar *data = g_key_file_to_data(repofile, &length, NULL);
+ auto fileLen = lseek(fd, 0, SEEK_END);
+ if (fileLen != static_cast<long>(length)) {
+ close(fd);
+ break;
+ }
+ if (fileLen > 0) {
+ std::unique_ptr<char[]> buf(new char[fileLen]);
+ lseek(fd, 0, SEEK_SET);
+ auto readed = read(fd, buf.get(), fileLen);
+ close(fd);
+ if (readed != fileLen || memcmp(buf.get(), data, readed) != 0)
+ break;
+ } else {
+ close(fd);
+ }
+ sameContent = true;
+ } while (false);
+
+ if (!sameContent) {
+ if (!g_key_file_save_to_file(repofile, repofname, error))
+ return FALSE;
+ }
+#endif
+
+ priv->enrollment_valid = TRUE;
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_setup:
+ * @context: a #DnfContext instance.
+ * @cancellable: A #GCancellable or %NULL
+ * @error: A #GError or %NULL
+ *
+ * Sets up the context ready for use.
+ *
+ * This function will not do significant amounts of i/o or download new
+ * metadata. Use dnf_context_setup_sack() if you want to populate the internal
+ * sack as well.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_setup(DnfContext *context,
+ GCancellable *cancellable,
+ GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ guint i;
+ guint j;
+ GHashTableIter hashiter;
+ gpointer hashkey, hashval;
+ g_autoptr(GString) buf = NULL;
+
+ if (libdnf::getGlobalMainConfig().plugins().getValue() && !pluginsDir.empty()) {
+ priv->plugins->loadPlugins(pluginsDir);
+ }
+ dnf_context_plugins_disable_enable(context);
+ PluginHookContextInitData initData(PLUGIN_MODE_CONTEXT, context);
+ priv->plugins->init(PLUGIN_MODE_CONTEXT, &initData);
+
+ if (!dnf_context_plugin_hook(context, PLUGIN_HOOK_ID_CONTEXT_PRE_CONF, nullptr, nullptr))
+ return FALSE;
+
+ /* check essential things are set */
+ if (priv->solv_dir == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "solv_dir not set");
+ return FALSE;
+ }
+
+ /* ensure directories exist */
+ auto repo_dir = dnf_context_get_repo_dir(context);
+ if (repo_dir[0]) {
+ if (!dnf_context_ensure_exists(repo_dir, error))
+ return FALSE;
+ }
+ if (priv->cache_dir != NULL) {
+ if (!dnf_context_ensure_exists(priv->cache_dir, error))
+ return FALSE;
+ }
+ if (priv->solv_dir != NULL) {
+ if (!dnf_context_ensure_exists(priv->solv_dir, error))
+ return FALSE;
+ }
+ if (priv->lock_dir != NULL) {
+ dnf_lock_set_lock_dir(priv->lock, priv->lock_dir);
+ if (!dnf_context_ensure_exists(priv->lock_dir, error))
+ return FALSE;
+ }
+ if (priv->install_root != NULL) {
+ if (!dnf_context_ensure_exists(priv->install_root, error))
+ return FALSE;
+ }
+
+ /* connect if set */
+ if (cancellable != NULL)
+ dnf_state_set_cancellable(priv->state, cancellable);
+
+ if (!dnf_context_globals_init (error))
+ return FALSE;
+
+ buf = g_string_new("");
+ g_hash_table_iter_init(&hashiter, priv->override_macros);
+ while (g_hash_table_iter_next(&hashiter, &hashkey, &hashval)) {
+ g_string_assign(buf, "%define ");
+ g_string_append(buf,(gchar*)hashkey);
+ g_string_append_c(buf, ' ');
+ g_string_append(buf,(gchar*)hashval);
+ /* Calling expand with %define (ignoring the return
+ * value) is apparently the way to change the global
+ * macro context.
+ */
+ free(rpmExpand(buf->str, NULL));
+ }
+
+ (void) dnf_context_get_base_arch(context);
+
+ /* find all the native archs */
+ if (!priv->native_arches) {
+ priv->native_arches = g_new0(gchar *, MAX_NATIVE_ARCHES);
+ for (i = 0; arch_map[i].base != NULL; i++) {
+ if (g_strcmp0(arch_map[i].base, priv->base_arch) == 0) {
+ for (j = 0; arch_map[i].native[j] != NULL; j++)
+ priv->native_arches[j] = g_strdup(arch_map[i].native[j]);
+ priv->native_arches[j++] = g_strdup("noarch");
+ break;
+ }
+ }
+ }
+
+ /* get info from OS release file */
+ if (priv->release_ver == NULL &&
+ !dnf_context_set_os_release(context, error))
+ return FALSE;
+
+ /* setup a file monitor on the rpmdb, if we're operating on the native / */
+ if (g_strcmp0(priv->install_root, "/") == 0) {
+ g_autofree char *rpmdb_path = rpmGetPath("%{_dbpath}", NULL);
+ g_autofree char *rpmdb_backend = rpmExpand("%{?_db_backend}", NULL);
+
+ if (rpmdb_path && rpmdb_backend) {
+ /* List of known RPM backends with their db files names; keep in sync
+ with RPM project's lib/backend/dbi.c:backends[] and its members.
+ or add public API to get to the actual DB file name into RPM */
+ struct _rpm_backends {
+ const char *name;
+ const char *filename;
+ } rpm_backends[] = {
+ { "sqlite", "rpmdb.sqlite" },
+ { "ndb", "Packages.db" },
+ { "bdb_ro", "Packages" },
+ { "bdb", "Packages" }
+ };
+ guint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (rpm_backends); ii++) {
+ if (g_str_equal(rpm_backends[ii].name, rpmdb_backend)) {
+ g_autofree char *filename = g_build_filename(rpmdb_path, rpm_backends[ii].filename, NULL);
+ if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+ g_autoptr(GFile) file_rpmdb = NULL;
+
+ file_rpmdb = g_file_new_for_path(filename);
+ priv->monitor_rpmdb = g_file_monitor_file(file_rpmdb,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ error);
+ if (priv->monitor_rpmdb == NULL)
+ return FALSE;
+ g_signal_connect(priv->monitor_rpmdb, "changed",
+ G_CALLBACK(dnf_context_rpmdb_changed_cb), context);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* copy any vendor distributed cached metadata */
+ if (!dnf_context_copy_vendor_cache(context, error))
+ return FALSE;
+ if (!dnf_context_copy_vendor_solv(context, error))
+ return FALSE;
+
+ /* initialize external frameworks where installed */
+ if (!dnf_context_setup_enrollments(context, error))
+ return FALSE;
+
+ /* initialize repos */
+ priv->repo_loader = dnf_repo_loader_new(context);
+ priv->repos = dnf_repo_loader_get_repos(priv->repo_loader, error);
+ if (priv->repos == NULL)
+ return FALSE;
+
+ if (!dnf_context_plugin_hook(context, PLUGIN_HOOK_ID_CONTEXT_CONF, nullptr, nullptr))
+ return FALSE;
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_run:
+ * @context: a #DnfContext instance.
+ * @cancellable: A #GCancellable or %NULL
+ * @error: A #GError or %NULL
+ *
+ * Runs the context installing or removing packages as required
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_run(DnfContext *context, GCancellable *cancellable, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ DnfState *state_local;
+ gboolean ret;
+
+ /* ensure transaction exists */
+ dnf_context_ensure_transaction(context);
+
+ /* connect if set */
+ dnf_state_reset(priv->state);
+ if (cancellable != NULL)
+ dnf_state_set_cancellable(priv->state, cancellable);
+
+ ret = dnf_state_set_steps(priv->state, error,
+ 5, /* depsolve */
+ 50, /* download */
+ 45, /* commit */
+ -1);
+ if (!ret)
+ return FALSE;
+
+ /* depsolve */
+ state_local = dnf_state_get_child(priv->state);
+ ret = dnf_transaction_depsolve(priv->transaction,
+ priv->goal,
+ state_local,
+ error);
+ if (!ret)
+ return FALSE;
+
+ /* this section done */
+ if (!dnf_state_done(priv->state, error))
+ return FALSE;
+
+ /* download */
+ state_local = dnf_state_get_child(priv->state);
+ ret = dnf_transaction_download(priv->transaction,
+ state_local,
+ error);
+ if (!ret)
+ return FALSE;
+
+ /* this section done */
+ if (!dnf_state_done(priv->state, error))
+ return FALSE;
+
+ /* commit set up transaction */
+ state_local = dnf_state_get_child(priv->state);
+ ret = dnf_transaction_commit(priv->transaction,
+ priv->goal,
+ state_local,
+ error);
+ if (!ret)
+ return FALSE;
+
+ /* this sack is no longer valid */
+ g_object_unref(priv->sack);
+ priv->sack = NULL;
+
+ /* this section done */
+ return dnf_state_done(priv->state, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_install:
+ * @context: a #DnfContext instance.
+ * @name: A package specification (NEVRA forms, provide, file provide, globs supported) e.g. "firefox"
+ * @error: A #GError or %NULL
+ *
+ * Finds a remote package and marks it to be installed.
+ *
+ * If multiple packages are available then only the newest package is installed.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_install(DnfContext *context, const gchar *name, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == NULL) {
+ dnf_state_reset (priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ g_auto(HySubject) subject = hy_subject_create(name);
+ g_auto(HySelector) selector = hy_subject_get_best_selector(subject, priv->sack, NULL, FALSE, NULL);
+ g_autoptr(GPtrArray) selector_matches = hy_selector_matches(selector);
+ if (selector_matches->len == 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_PACKAGE_NOT_FOUND,
+ "No package matches '%s'", name);
+ return FALSE;
+ }
+
+ if (!hy_goal_install_selector(priv->goal, selector, error))
+ return FALSE;
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_remove:
+ * @context: a #DnfContext instance.
+ * @name: A package specification (NEVRA forms, provide, file provide, globs supported) e.g. "firefox"
+ * @error: A #GError or %NULL
+ *
+ * Finds an installed package and marks it to be removed.
+ *
+ * If multiple packages are available, all of them will be removed.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_remove(DnfContext *context, const gchar *name, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create sack and add repos */
+ if (priv->sack == NULL) {
+ dnf_state_reset(priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ libdnf::Query query(priv->sack, libdnf::Query::ExcludeFlags::APPLY_EXCLUDES);
+ query.installed();
+ auto ret = query.filterSubject(name, nullptr, false, true, true, true);
+ if (!ret.first) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_PACKAGE_NOT_FOUND,
+ "No installed package matches '%s'", name);
+ return FALSE;
+ }
+
+ g_autoptr(GPtrArray) packages = query.run();
+
+ /* add each package */
+ for (guint i = 0; i < packages->len; i++) {
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(packages, i));
+ hy_goal_erase(priv->goal, pkg);
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_update:
+ * @context: a #DnfContext instance.
+ * @name: A package specification (NEVRA forms, provide, file provide, globs supported) e.g. "firefox"
+ * @error: A #GError or %NULL
+ *
+ * Finds an installed and remote package and marks it to be updated.
+ *
+ * If multiple packages are available then the newest package is updated to.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_update(DnfContext *context, const gchar *name, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create sack and add repos */
+ if (priv->sack == NULL) {
+ dnf_state_reset(priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ g_auto(HySubject) subject = hy_subject_create(name);
+ g_auto(HySelector) selector = hy_subject_get_best_selector(subject, priv->sack, NULL, FALSE, NULL);
+ g_autoptr(GPtrArray) selector_matches = hy_selector_matches(selector);
+ if (selector_matches->len == 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_PACKAGE_NOT_FOUND,
+ "No package matches '%s'", name);
+ return FALSE;
+ }
+
+ int ret = hy_goal_upgrade_selector(priv->goal, selector);
+ if (ret != 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ ret,
+ "Ill-formed Selector '%s'", name);
+ return FALSE;
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_update_all:
+ * @context: a #DnfContext instance.
+ * @error: A #GError or %NULL
+ *
+ * Update all packages.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.7.0
+ **/
+gboolean
+dnf_context_update_all (DnfContext *context,
+ GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create sack and add repos */
+ if (priv->sack == NULL) {
+ dnf_state_reset(priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ /* update whole solvables */
+ hy_goal_upgrade_all (priv->goal);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_distrosync:
+ * @context: a #DnfContext instance.
+ * @name: A package specification (NEVRA forms, provide, file provide, globs supported) e.g. "firefox"
+ * @error: A #GError or %NULL
+ *
+ * Finds an installed and remote package and marks it to be synchronized with remote version.
+ *
+ * If multiple packages are available then the newest package is synchronized to.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.62.0
+ **/
+gboolean
+dnf_context_distrosync(DnfContext *context, const gchar *name, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create sack and add repos */
+ if (priv->sack == NULL) {
+ dnf_state_reset(priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ g_auto(HySubject) subject = hy_subject_create(name);
+ g_auto(HySelector) selector = hy_subject_get_best_selector(subject, priv->sack, NULL, FALSE,
+ NULL);
+ g_autoptr(GPtrArray) selector_matches = hy_selector_matches(selector);
+ if (selector_matches->len == 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_PACKAGE_NOT_FOUND,
+ "No package matches '%s'", name);
+ return FALSE;
+ }
+
+ if (hy_goal_distupgrade_selector(priv->goal, selector))
+ return FALSE;
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_distrosync_all:
+ * @context: a #DnfContext instance.
+ * @error: A #GError or %NULL
+ *
+ * Distro-sync all packages.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.62.0
+ **/
+gboolean
+dnf_context_distrosync_all (DnfContext *context,
+ GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* create sack and add repos */
+ if (priv->sack == NULL) {
+ dnf_state_reset(priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error))
+ return FALSE;
+ }
+
+ /* distrosync whole solvables */
+ hy_goal_distupgrade_all (priv->goal);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_repo_set_data:
+ **/
+static gboolean
+dnf_context_repo_set_data(DnfContext *context,
+ const gchar *repo_id,
+ DnfRepoEnabled enabled,
+ GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ bool found = false;
+
+ /* set repos with a matching ID */
+ for (guint i = 0; i < priv->repos->len; ++i) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (fnmatch(repo_id, dnf_repo_get_id(repo), 0) == 0) {
+ dnf_repo_set_enabled(repo, enabled);
+ found = true;
+ }
+ }
+
+ /* nothing found */
+ if (!found) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "repo %s not found", repo_id);
+ return FALSE;
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_repo_enable:
+ * @context: a #DnfContext instance.
+ * @repo_id: A repo_id, e.g. "fedora-rawhide"
+ * @error: A #GError or %NULL
+ *
+ * Enables a specific repo(s).
+ * Wildcard pattern is supported.
+ *
+ * This must be done before dnf_context_setup() is called.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_repo_enable(DnfContext *context,
+ const gchar *repo_id,
+ GError **error) try
+{
+ return dnf_context_repo_set_data(context, repo_id,
+ DNF_REPO_ENABLED_PACKAGES |
+ DNF_REPO_ENABLED_METADATA, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_repo_disable:
+ * @context: a #DnfContext instance.
+ * @repo_id: A repo_id, e.g. "fedora-rawhide"
+ * @error: A #GError or %NULL
+ *
+ * Disables a specific repo(s).
+ * Wildcard pattern is supported.
+ *
+ * This must be done before dnf_context_setup() is called.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_repo_disable(DnfContext *context,
+ const gchar *repo_id,
+ GError **error) try
+{
+ return dnf_context_repo_set_data(context, repo_id,
+ DNF_REPO_ENABLED_NONE, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_commit:(skip)
+ * @context: a #DnfContext instance.
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ *
+ * Commits a context, which applies changes to the live system.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_context_commit(DnfContext *context, DnfState *state, GError **error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+
+ /* ensure transaction exists */
+ dnf_context_ensure_transaction(context);
+
+ /* run the transaction */
+ return dnf_transaction_commit(priv->transaction,
+ priv->goal,
+ state,
+ error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_context_invalidate_full:
+ * @context: a #DnfContext instance.
+ * @message: the reason for invalidating
+ * @flags: a #DnfContextInvalidateFlags, e.g. %DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT
+ *
+ * Informs the context that the certain parts of the context may no longer be
+ * in sync or valid.
+ *
+ * Since: 0.2.1
+ **/
+void
+dnf_context_invalidate_full(DnfContext *context,
+ const gchar *message,
+ DnfContextInvalidateFlags flags)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ g_debug("Msg: %s", message);
+ if (flags & DNF_CONTEXT_INVALIDATE_FLAG_RPMDB)
+ g_signal_emit(context, signals [SIGNAL_INVALIDATE], 0, message);
+ if (flags & DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT)
+ priv->enrollment_valid = FALSE;
+}
+
+/**
+ * dnf_context_invalidate:
+ * @context: a #DnfContext instance.
+ * @message: the reason for invalidating
+ *
+ * Emits a signal which signals that the context is invalid.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_context_invalidate(DnfContext *context, const gchar *message)
+{
+ dnf_context_invalidate_full(context, message,
+ DNF_CONTEXT_INVALIDATE_FLAG_RPMDB);
+}
+
+/**
+ * dnf_context_clean_cache:
+ * @context: a #DnfContext instance.
+ * @flags: #DnfContextCleanFlags flag, e.g. %DNF_CONTEXT_CLEAN_EXPIRE_CACHE
+ * @error: a #GError instance
+ *
+ * Clean the cache content in the current cache directory based
+ * on the context flags. A valid cache directory and lock directory
+ * is expected to be set prior to using this function. Use it with care.
+ *
+ * Currently support four different clean flags:
+ * 1: DNF_CONTEXT_CLEAN_EXPIRE_CACHE: Eliminate the entries that give information about cache entries' age. i.e: 'repomd.xml' will be deleted in libdnf case
+ * 2: DNF_CONTEXT_CLEAN_PACKAGES: Eliminate any cached packages. i.e: 'packages' folder will be deleted
+ * 3: DNF_CONTEXT_CLEAN_METADATA: Eliminate all of the files which libdnf uses to determine remote availability of packages. i.e: 'repodata'folder and 'metalink.xml' will be deleted
+ * 4: DNF_CONTEXT_CLEAN_ALL: Does all the actions above and clean up other files that are generated due to various reasons. e.g: cache directories from previous version of operating system
+ *
+ * Note: when DNF_CONTEXT_CLEAN_ALL flag is seen, the other flags will be ignored
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.9.4
+ **/
+gboolean
+dnf_context_clean_cache(DnfContext *context,
+ DnfContextCleanFlags flags,
+ GError **error) try
+{
+ g_autoptr(GPtrArray) suffix_list = g_ptr_array_new();
+ const gchar* directory_location;
+ gboolean ret = TRUE;
+ guint lock_id = 0;
+
+ /* Set up the context if it hasn't been set earlier */
+ if (!dnf_context_setup(context, NULL, error))
+ return FALSE;
+
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ /* We expect cache directories to be set when cleaning cache entries */
+ if (priv->cache_dir == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "No cache dir set");
+ return FALSE;
+ }
+
+ /* When clean all flags show up, we remove everything from cache directory */
+ if (flags & DNF_CONTEXT_CLEAN_ALL) {
+ return dnf_remove_recursive(priv->cache_dir, error);
+ }
+
+ /* We acquire the metadata related lock */
+ lock_id = dnf_lock_take(priv->lock,
+ DNF_LOCK_TYPE_METADATA,
+ DNF_LOCK_MODE_PROCESS,
+ error);
+ if (lock_id == 0)
+ return FALSE;
+
+ /* After the above setup is done, we prepare file extensions based on flag types */
+ if (flags & DNF_CONTEXT_CLEAN_PACKAGES)
+ g_ptr_array_add(suffix_list, (char*) "packages");
+ if (flags & DNF_CONTEXT_CLEAN_METADATA) {
+ g_ptr_array_add(suffix_list, (char*) "metalink.xml");
+ g_ptr_array_add(suffix_list, (char*) "repodata");
+ }
+ if (flags & DNF_CONTEXT_CLEAN_EXPIRE_CACHE)
+ g_ptr_array_add(suffix_list, (char*) "repomd.xml");
+
+ /* Add a NULL terminator for future looping */
+ g_ptr_array_add(suffix_list, NULL);
+
+ /* We then start looping all of the repos to perform file deletion */
+ for (guint counter = 0; counter < priv->repos->len; counter++) {
+ auto src = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, counter));
+ gboolean deleteable_repo = dnf_repo_get_kind(src) == DNF_REPO_KIND_REMOTE;
+ directory_location = dnf_repo_get_location(src);
+
+ /* We check if the repo is qualified to be cleaned */
+ if (deleteable_repo &&
+ g_file_test(directory_location, G_FILE_TEST_EXISTS)) {
+ ret = dnf_delete_files_matching(directory_location,
+ (const char* const*) suffix_list->pdata,
+ error);
+ if(!ret)
+ goto out;
+ }
+ }
+
+ out:
+ /* release the acquired lock */
+ if (!dnf_lock_release(priv->lock, lock_id, error))
+ return FALSE;
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+/**
+ * dnf_context_new:
+ *
+ * Creates a new #DnfContext.
+ *
+ * Returns: (transfer full): a #DnfContext
+ *
+ * Since: 0.1.0
+ **/
+DnfContext *
+dnf_context_new(void)
+{
+ return DNF_CONTEXT(g_object_new(DNF_TYPE_CONTEXT, NULL));
+}
+
+/**
+ * dnf_context_disable_plugins:
+ * @plugin_name: a name pattern of plugins to disable.
+ *
+ * Adds name pattern into list of disabled plugins.
+ * NULL or empty string means clear the list.
+ * The list has lower priority than list of enabled plugins.
+ *
+ * Since: 0.41.0
+ **/
+void
+dnf_context_disable_plugins(const gchar * plugin_name_pattern)
+{
+ if (!plugin_name_pattern || plugin_name_pattern[0] == '\0') {
+ pluginsDisabled.clear();
+ } else {
+ pluginsDisabled.insert(plugin_name_pattern);
+ }
+}
+
+/**
+ * dnf_context_enable_plugins:
+ * @plugin_name: a name pattern of plugins to enable.
+ *
+ * Adds name pattern into list of enabled plugins.
+ * NULL or empty string means clear the list.
+ * The list has higher priority than list of disabled plugins.
+ *
+ * Since: 0.41.0
+ **/
+void
+dnf_context_enable_plugins(const gchar * plugin_name_pattern)
+{
+ if (!plugin_name_pattern || plugin_name_pattern[0] == '\0') {
+ pluginsEnabled.clear();
+ } else {
+ pluginsEnabled.insert(plugin_name_pattern);
+ }
+}
+
+/**
+ * dnf_context_get_disabled_plugins:
+ *
+ * List of name patterns of disabled plugins.
+ *
+ * Returns: NULL terminated array. Caller must free it.
+ *
+ * Since: 0.41.0
+ **/
+gchar **
+dnf_context_get_disabled_plugins()
+{
+ gchar ** ret = g_new0(gchar*, pluginsDisabled.size() + 1);
+ size_t i = 0;
+ for (auto & namePattern : pluginsDisabled) {
+ ret[i++] = g_strdup(namePattern.c_str());
+ }
+ return ret;
+}
+
+/**
+ * dnf_context_get_enabled_plugins:
+ *
+ * List of name patterns of enabled plugins.
+ *
+ * Returns: NULL terminated array. Caller must free it.
+ *
+ * Since: 0.41.0
+ **/
+gchar **
+dnf_context_get_enabled_plugins()
+{
+ gchar ** ret = g_new0(gchar*, pluginsEnabled.size() + 1);
+ size_t i = 0;
+ for (auto & namePattern : pluginsEnabled) {
+ ret[i++] = g_strdup(namePattern.c_str());
+ }
+ return ret;
+}
+
+/**
+ * dnf_context_get_plugins_all_disabled:
+ * @context: a #DnfContext instance.
+ *
+ * Gets plugins global configuration value.
+ *
+ * Returns: %TRUE if plugins are disabled
+ *
+ * Since: 0.41.0
+ **/
+gboolean
+dnf_context_get_plugins_all_disabled()
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ return !mainConf.plugins().getValue();
+}
+
+/**
+ * dnf_context_set_plugins_all_disabled:
+ * @context: a #DnfContext instance.
+ *
+ * Disable or enable plugins.
+ * Sets plugins global configuration value.
+ * To take effect must be called before dnf_context_setup().
+ *
+ * Since: 0.41.0
+ **/
+void
+dnf_context_set_plugins_all_disabled(gboolean disabled)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig(false);
+ mainConf.plugins().set(libdnf::Option::Priority::RUNTIME, !disabled);
+}
+
+/**
+ * dnf_context_get_plugins_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Gets path to plugin directory.
+ *
+ * Returns: (transfer none): the plugins dir
+ *
+ * Since: 0.21.0
+ **/
+const char *
+dnf_context_get_plugins_dir(DnfContext * context)
+{
+ return pluginsDir.c_str();
+}
+
+/**
+ * dnf_context_set_plugins_dir:
+ * @context: a #DnfContext instance.
+ *
+ * Sets path to plugin directory.
+ * To take effect must be called before dnf_context_setup().
+ * Empty path disable loading of plugins at all.
+ *
+ * Since: 0.21.0
+ **/
+void
+dnf_context_set_plugins_dir(DnfContext * context, const char * plugins_dir)
+{
+ pluginsDir = plugins_dir ? plugins_dir : "";
+}
+
+bool
+dnf_context_plugin_hook(DnfContext * context, PluginHookId id, DnfPluginHookData * hookData, DnfPluginError * error)
+{
+ DnfContextPrivate *priv = GET_PRIVATE(context);
+ return priv->plugins->hook(id, hookData, error);
+}
+
+gchar *
+dnf_context_get_module_report(DnfContext * context)
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == nullptr) {
+ return nullptr;
+ }
+ auto container = dnf_sack_get_module_container(priv->sack);
+ if (container == nullptr) {
+ return nullptr;
+ }
+ auto report = container->getReport();
+ if (report.empty()) {
+ return nullptr;
+ }
+ return g_strdup(report.c_str());
+}
+
+DnfContext *
+pluginGetContext(DnfPluginInitData * data)
+{
+ if (!data) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with data == nullptr", __func__));
+ return nullptr;
+ }
+ if (data->mode != PLUGIN_MODE_CONTEXT) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with pluginMode == %i", __func__, data->mode));
+ return nullptr;
+ }
+ return (static_cast<PluginHookContextInitData *>(data)->context);
+}
+
+static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>>
+recompute_modular_filtering(libdnf::ModulePackageContainer * moduleContainer, DnfSack * sack, std::vector<const char *> & hotfixRepos)
+{
+ auto solver_errors = dnf_sack_filter_modules_v2(
+ sack, moduleContainer, hotfixRepos.data(), nullptr, nullptr, true, false, false);
+ if (solver_errors.second == libdnf::ModulePackageContainer::ModuleErrorType::NO_ERROR) {
+ return {};
+ }
+ auto formated_problem = libdnf::Goal::formatAllProblemRules(solver_errors.first);
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> ret;
+ ret.emplace_back(std::make_tuple(solver_errors.second, std::move(formated_problem), std::string()));
+ return ret;
+}
+
+/* This is subtly different from the C++ version above: it passes NULL as the
+ * modular container to `dnf_sack_filter_modules_v2` which has the effect of
+ * throwing away all transient modular changes and reloading from disk. This is
+ * used by dnf_context_reset_all_modules(). */
+static gboolean
+recompute_modular_filtering(DnfContext * context, DnfSack * sack, GError ** error)
+{
+ DnfContextPrivate * priv = GET_PRIVATE(context);
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ try {
+ dnf_sack_filter_modules_v2(sack, nullptr, hotfixRepos.data(), priv->install_root,
+ priv->platform_module, false, false, false);
+ } catch (libdnf::ModulePackageContainer::ConflictException & exception) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FAILED, "%s", exception.what());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* See header docstring; you likely want dnf_context_module_reset instead. */
+gboolean
+dnf_context_reset_modules(DnfContext * context, DnfSack * sack, const char ** module_names, GError ** error) try
+{
+ assert(sack);
+ assert(module_names);
+
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ return TRUE;
+ }
+ for (const char ** names = module_names; *names != NULL; ++names) {
+ try {
+ container->reset(*names);
+ } catch (libdnf::ModulePackageContainer::NoModuleException & exception) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FAILED, "%s", exception.what());
+ return FALSE;
+ }
+ }
+ container->save();
+ container->updateFailSafeData();
+ return recompute_modular_filtering(context, sack, error);
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_context_reset_all_modules(DnfContext * context, DnfSack * sack, GError ** error) try
+{
+ assert(sack);
+
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ return TRUE;
+ }
+ auto all_modules = container->getModulePackages();
+ std::unordered_set<std::string> names;
+ for (auto module: all_modules) {
+ names.emplace(module->getName());
+ }
+ for (auto & name: names) {
+ container->reset(name);
+ }
+ //container->save();
+ //container->updateFailSafeData();
+ return recompute_modular_filtering(context, sack, error);
+} CATCH_TO_GERROR(FALSE)
+
+/// module dict { name : {stream : [module packages] }
+static std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> create_module_dict(
+ const std::vector<libdnf::ModulePackage *> & modules)
+{
+ std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> data;
+ for (auto * module : modules) {
+ data[module->getName()][module->getStream()].push_back(module);
+ }
+ return data;
+}
+
+/// Modify module_dict => Keep only single relevant stream
+/// If more streams it keeps enabled or default stream
+/// If `enable` is true, also marks the selected stream as enabled.
+/// Returns errors found as: vec<(error type, error msg, module name)>
+static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> modify_module_dict_and_enable_stream(std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>> & module_dict, libdnf::ModulePackageContainer & container, bool enable)
+{
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+ for (auto & module_dict_iter : module_dict) {
+ auto & name = module_dict_iter.first;
+ auto & stream_dict = module_dict_iter.second;
+ auto moduleState = container.getModuleState(name);
+ if (stream_dict.size() > 1) {
+ if (moduleState != libdnf::ModulePackageContainer::ModuleState::ENABLED
+ && moduleState != libdnf::ModulePackageContainer::ModuleState::DEFAULT) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS,
+ tfm::format(_("Cannot enable more streams from module '%s' at the same time"), name), name));
+ return messages;
+ }
+ const auto enabledOrDefaultStream = moduleState == libdnf::ModulePackageContainer::ModuleState::ENABLED ?
+ container.getEnabledStream(name) : container.getDefaultStream(name);
+ auto modules_iter = stream_dict.find(enabledOrDefaultStream);
+ if (modules_iter == stream_dict.end()) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS,
+ tfm::format(_("Cannot enable more streams from module '%s' at the same time"), name), name));
+ return messages;
+ }
+ if (enable) {
+ try {
+ container.enable(name, modules_iter->first);
+ } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ tfm::format(_("Cannot enable module '%1$s' stream '%2$s': State of module already modified"),
+ name, modules_iter->first), name));
+ }
+ }
+ for (auto iter = stream_dict.begin(); iter != stream_dict.end(); ) {
+ if (iter->first != enabledOrDefaultStream) {
+ stream_dict.erase(iter++);
+ } else {
+ ++iter;
+ }
+ }
+ } else if (enable) {
+ for (auto iter : stream_dict) {
+ try {
+ container.enable(name, iter.first);
+ } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ tfm::format(_("Cannot enable module '%1$s' stream '%2$s': State of module already modified"),
+ name, iter.first), name));
+ }
+ }
+ }
+ if (stream_dict.size() != 1) {
+ throw std::runtime_error("modify_module_dict_and_enable_stream() did not modify output correctly!!!");
+ }
+ }
+ return messages;
+}
+
+// Attempts to parse the module spec and returns the parsed Nsvcap with the list
+// of module packages which matched.
+static std::pair<std::unique_ptr<libdnf::Nsvcap>, std::vector< libdnf::ModulePackage*>> resolve_module_spec(const std::string & module_spec, libdnf::ModulePackageContainer & container)
+{
+ std::unique_ptr<libdnf::Nsvcap> nsvcapObj(new libdnf::Nsvcap);
+ for (std::size_t i = 0; HY_MODULE_FORMS_MOST_SPEC[i] != _HY_MODULE_FORM_STOP_; ++i) {
+ if (nsvcapObj->parse(module_spec.c_str(), HY_MODULE_FORMS_MOST_SPEC[i])) {
+ auto result_modules = container.query(nsvcapObj->getName(),
+ nsvcapObj->getStream(),
+ nsvcapObj->getVersion(),
+ nsvcapObj->getContext(),
+ nsvcapObj->getArch());
+ if (!result_modules.empty()) {
+ return std::make_pair(std::move(nsvcapObj), std::move(result_modules));
+ }
+ }
+ }
+ return {};
+}
+
+static std::vector<std::string>
+report_problems(const std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> & messages)
+{
+ libdnf::ModulePackageContainer::ModuleErrorType typeMessage;
+ std::string report;
+ std::string argument;
+ auto logger(libdnf::Log::getLogger());
+ std::vector<std::string> errors;
+ for (auto & message : messages) {
+ std::tie(typeMessage, report, argument) = message;
+ switch (typeMessage) {
+ case libdnf::ModulePackageContainer::ModuleErrorType::NO_ERROR:
+ break;
+ case libdnf::ModulePackageContainer::ModuleErrorType::INFO:
+ logger->notice(report);
+ break;
+ case libdnf::ModulePackageContainer::ModuleErrorType::ERROR_IN_DEFAULTS:
+ logger->warning(tfm::format(_("Modular dependency problem with Defaults: %s"), report.c_str()));
+ break;
+ case libdnf::ModulePackageContainer::ModuleErrorType::ERROR_IN_LATEST:
+ logger->warning(tfm::format(_("Modular dependency problem with the latest modules: %s"),
+ report.c_str()));
+ break;
+ case libdnf::ModulePackageContainer::ModuleErrorType::ERROR:
+ errors.push_back(tfm::format(_("Modular dependency problem: %s"), report.c_str()));
+ break;
+ case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULES:
+ case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC:
+ case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_ENABLE_MULTIPLE_STREAMS:
+ case libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE:
+ errors.push_back(report);
+ break;
+ }
+ }
+ return errors;
+}
+
+static std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>>
+modules_reset_or_disable(libdnf::ModulePackageContainer & container, const char ** module_specs, bool reset)
+{
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+
+ for (const char ** specs = module_specs; *specs != NULL; ++specs) {
+ auto resolved_spec = resolve_module_spec(*specs, container);
+ if (!resolved_spec.first) {
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ continue;
+ }
+ if (!resolved_spec.first->getStream().empty() || !resolved_spec.first->getProfile().empty() ||
+ !resolved_spec.first->getVersion().empty() || !resolved_spec.first->getContext().empty()) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::INFO,
+ tfm::format(_("Only module name is required. Ignoring unneeded information in argument: '%s'"), *specs),
+ *specs));
+ }
+ std::unordered_set<std::string> names;
+ for (auto * module : resolved_spec.second) {
+ names.insert(std::move(module->getName()));
+ }
+ for (auto & name : names) {
+ if (reset) {
+ try {
+ container.reset(name);
+ } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ tfm::format(_("Cannot reset module '%s': State of module already modified"), name), name));
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ }
+ } else {
+ try {
+ container.disable(name);
+ } catch (libdnf::ModulePackageContainer::EnableMultipleStreamsException &) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ tfm::format(_("Cannot disable module '%s': State of module already modified"), name), name));
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ }
+ }
+ }
+ }
+
+ return messages;
+}
+
+gboolean
+dnf_context_module_enable(DnfContext * context, const char ** module_specs, GError ** error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == nullptr) {
+ dnf_state_reset (priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error)) {
+ return FALSE;
+ }
+ }
+
+ DnfSack * sack = priv->sack;
+ assert(sack);
+ assert(module_specs);
+
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available"));
+ return FALSE;
+ }
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+
+ std::vector<std::pair<const char *, std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>>>> all_resolved_module_dicts;
+ for (const char ** specs = module_specs; *specs != NULL; ++specs) {
+ auto resolved_spec = resolve_module_spec(*specs, *container);
+ if (!resolved_spec.first) {
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ continue;
+ }
+ if (!resolved_spec.first->getProfile().empty() || !resolved_spec.first->getVersion().empty() ||
+ !resolved_spec.first->getContext().empty()) {
+ messages.emplace_back(std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::INFO,
+ tfm::format(_("Ignoring unneeded information in argument: '%s'"), *specs),
+ *specs));
+ }
+ auto module_dict = create_module_dict(resolved_spec.second);
+ auto message = modify_module_dict_and_enable_stream(module_dict, *container, true);
+ if (!message.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(message.begin()), std::make_move_iterator(message.end()));
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ } else {
+ all_resolved_module_dicts.emplace_back(make_pair(*specs, std::move(module_dict)));
+ }
+ }
+
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos);
+ if (!solver_error.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end()));
+ }
+ for (auto & pair : all_resolved_module_dicts) {
+ for (auto module_dict_iter : pair.second) {
+ for (auto & stream_dict_iter : module_dict_iter.second) {
+ try {
+ container->enableDependencyTree(stream_dict_iter.second);
+ } catch (const libdnf::ModulePackageContainer::EnableMultipleStreamsException & exception) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ tfm::format(_("Problem during enablement of dependency tree for module '%1$s' stream '%2$s': %3$s"),
+ module_dict_iter.first, stream_dict_iter.first, exception.what()), pair.first));
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), pair.first), pair.first));
+ }
+ }
+ }
+ }
+
+ auto errors = report_problems(messages);
+ if (!errors.empty()) {
+ std::string final_errmsg (_("Problems appeared for module enable request:"));
+ for (const auto &errmsg : errors) {
+ final_errmsg += "\n - " + errmsg;
+ }
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, final_errmsg.c_str());
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_context_module_install(DnfContext * context, const char ** module_specs, GError ** error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == nullptr) {
+ dnf_state_reset (priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error)) {
+ return FALSE;
+ }
+ }
+
+ DnfSack * sack = priv->sack;
+ assert(sack);
+ assert(module_specs);
+
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available"));
+ return FALSE;
+ }
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+
+ // vec<(module spec, Nsvcap, module dict)>
+ std::vector<std::tuple<const char *, std::unique_ptr<libdnf::Nsvcap>, std::map<std::string, std::map<std::string, std::vector<libdnf::ModulePackage *>>>>> all_resolved_module_dicts;
+ for (const char ** specs = module_specs; *specs != NULL; ++specs) {
+ auto resolved_spec = resolve_module_spec(*specs, *container);
+ if (!resolved_spec.first) {
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ continue;
+ }
+ auto module_dict = create_module_dict(resolved_spec.second);
+ auto message = modify_module_dict_and_enable_stream(module_dict, *container, true);
+ if (!message.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(message.begin()), std::make_move_iterator(message.end()));
+ messages.emplace_back(
+ std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
+ tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
+ } else {
+ all_resolved_module_dicts.emplace_back(make_tuple(*specs, std::move(resolved_spec.first), std::move(module_dict)));
+ }
+ }
+
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos);
+ if (!solver_error.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end()));
+ }
+
+ // this code is based on dnf's ModuleBase.install()
+
+ for (auto it = std::make_move_iterator(all_resolved_module_dicts.begin());
+ it != std::make_move_iterator(all_resolved_module_dicts.end()); it++) {
+ auto module_spec = std::get<0>(*it);
+ auto nsvcap_obj = std::get<1>(*it);
+ auto module_dict = std::get<2>(*it);
+ for (auto module_dict_iter : module_dict) {
+ // this was checked in modify_module_dict_and_enable_stream()
+ assert(module_dict_iter.second.size() == 1);
+
+ for (auto & stream_dict_iter : module_dict_iter.second) {
+ try {
+ container->enableDependencyTree(stream_dict_iter.second);
+
+ std::vector<libdnf::ModulePackage*> active_modules;
+ for (auto &modpkg : stream_dict_iter.second) {
+ if (container->isModuleActive(modpkg)) {
+ active_modules.push_back(modpkg);
+ }
+ }
+
+ if (active_modules.empty()) {
+ throw std::runtime_error(tfm::format(_("No active module packages found for module spec '%s'"), module_spec));
+ }
+
+ auto latest = container->getLatestModule(active_modules, true);
+ if (latest->getRepoID() == LIBDNF_MODULE_FAIL_SAFE_REPO_NAME) {
+ throw std::runtime_error(tfm::format(_("Cannot install module '%s' from fail-safe repository"), latest->getFullIdentifier().c_str()));
+ }
+
+ std::vector<libdnf::ModuleProfile> profiles;
+ if (nsvcap_obj->getProfile() != "") {
+ profiles = latest->getProfiles(nsvcap_obj->getProfile());
+ if (profiles.empty()) {
+ throw std::runtime_error(tfm::format(_("No profile found matching '%s'"), nsvcap_obj->getProfile().c_str()));
+ }
+ } else {
+ // This queries the distro-level modulemd-defaults.
+ auto default_profiles = container->getDefaultProfiles(latest->getName(), latest->getStream());
+ for (auto & profileName : default_profiles) {
+ auto matching = latest->getProfiles(profileName);
+ profiles.insert(profiles.begin(), matching.begin(), matching.end());
+ }
+ if (profiles.empty()) {
+ throw std::runtime_error("No default profile found for " + latest->getFullIdentifier());
+ }
+ }
+
+ g_autoptr(GPtrArray) pkgnames = g_ptr_array_new_with_free_func (g_free);
+ auto nsvca = latest->getFullIdentifier();
+ for (const auto &profile : profiles) {
+ container->install(latest, profile.getName());
+ for (const auto &pkgname : profile.getContent()) {
+ g_ptr_array_add(pkgnames, g_strdup(pkgname.c_str()));
+ }
+ }
+ g_ptr_array_add(pkgnames, NULL);
+
+ g_autoptr(GPtrArray) artifacts = g_ptr_array_new_with_free_func (g_free);
+ for (auto modpkg : active_modules) {
+ for (const auto &nevra : modpkg->getArtifacts()) {
+ g_ptr_array_add(artifacts, g_strdup (nevra.c_str()));
+ }
+ }
+ g_ptr_array_add (artifacts, NULL);
+
+ hy_autoquery HyQuery base_nosrc_query = hy_query_create(priv->sack);
+ const char *src_arches[] = {"src", "nosrc", NULL};
+ hy_query_filter_in(base_nosrc_query, HY_PKG_ARCH, HY_NEQ, src_arches);
+
+ hy_autoquery HyQuery hotfix_query = hy_query_clone(base_nosrc_query);
+ hy_query_filter_in(hotfix_query, HY_PKG_NAME, HY_EQ, (const char**)pkgnames->pdata);
+ hy_query_filter_in(hotfix_query, HY_PKG_REPONAME, HY_EQ, (const char**)hotfixRepos.data());
+
+ hy_autoquery HyQuery install_base_query = hy_query_clone (base_nosrc_query);
+ hy_query_filter_in(install_base_query, HY_PKG_NEVRA_STRICT, HY_EQ, (const char**)artifacts->pdata);
+ hy_query_union(install_base_query, hotfix_query);
+
+ for (char **it = (char**)pkgnames->pdata; it && *it; it++) {
+ const char *pkgname = *it;
+ hy_autoquery HyQuery query = hy_query_clone(install_base_query);
+ hy_query_filter(query, HY_PKG_NAME, HY_EQ, pkgname);
+ if (hy_query_is_empty(query)) {
+ // package can also be non-modular or part of another stream
+ hy_query_free(query);
+ query = hy_query_clone(base_nosrc_query);
+ hy_query_filter(query, HY_PKG_NAME, HY_EQ, pkgname);
+ if (hy_query_is_empty(query)) {
+ throw std::runtime_error(tfm::format(_("No match for package '%s' for module spec %s"), pkgname, module_spec));
+ }
+ }
+ g_autoptr(GError) local_error = NULL;
+ g_auto(HySelector) selector = hy_query_to_selector(query);
+ if (!hy_goal_install_selector(priv->goal, selector, &local_error))
+ throw std::runtime_error(local_error->message);
+ }
+ } catch (const std::exception & ex) {
+ messages.emplace_back(std::make_tuple(
+ libdnf::ModulePackageContainer::ModuleErrorType::ERROR,
+ tfm::format(_("Problem during install for module '%1$s' stream '%2$s': %3$s"),
+ module_dict_iter.first, stream_dict_iter.first, ex.what()), module_spec));
+ }
+ }
+ }
+ }
+
+ auto errors = report_problems(messages);
+ if (!errors.empty()) {
+ std::string final_errmsg (_("Problems appeared for module install request:"));
+ for (const auto &errmsg : errors) {
+ final_errmsg += "\n - " + errmsg;
+ }
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, final_errmsg.c_str());
+ return FALSE;
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+static gboolean
+context_modules_reset_or_disable(DnfContext * context, const char ** module_specs, GError ** error, bool reset)
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == nullptr) {
+ dnf_state_reset (priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error)) {
+ return FALSE;
+ }
+ }
+
+ DnfSack * sack = priv->sack;
+ assert(module_specs);
+
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available"));
+ return FALSE;
+ }
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+
+ auto disable_errors = modules_reset_or_disable(*container, module_specs, reset);
+ if (!disable_errors.empty()) {
+ messages.insert(
+ messages.end(),
+ std::make_move_iterator(disable_errors.begin()),
+ std::make_move_iterator(disable_errors.end()));
+ }
+
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos);
+ if (!solver_error.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end()));
+ }
+
+ auto errors = report_problems(messages);
+ if (!errors.empty()) {
+ std::string final_errmsg (reset ? _("Problems appeared for module reset request:")
+ : _("Problems appeared for module disable request:"));
+ for (const auto &errmsg : errors) {
+ final_errmsg += "\n - " + errmsg;
+ }
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, final_errmsg.c_str());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gboolean
+dnf_context_module_disable(DnfContext * context, const char ** module_specs, GError ** error) try
+{
+ return context_modules_reset_or_disable(context, module_specs, error, false);
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_context_module_disable_all(DnfContext * context, GError ** error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+
+ /* create sack and add sources */
+ if (priv->sack == nullptr) {
+ dnf_state_reset (priv->state);
+ if (!dnf_context_setup_sack(context, priv->state, error)) {
+ return FALSE;
+ }
+ }
+
+ DnfSack * sack = priv->sack;
+ auto container = dnf_sack_get_module_container(sack);
+ if (!container) {
+ return TRUE;
+ }
+
+ auto all_modules = container->getModulePackages();
+ for (auto & module: all_modules) {
+ container->disable(module->getName());
+ }
+
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+
+ std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;
+ auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos);
+ if (!solver_error.empty()) {
+ messages.insert(
+ messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end()));
+ }
+
+ auto errors = report_problems(messages);
+ if (!errors.empty()) {
+ std::string final_errmsg (_("Problems appeared for module disable request:"));
+ for (const auto &errmsg : errors) {
+ final_errmsg += "\n - " + errmsg;
+ }
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, final_errmsg.c_str());
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_context_module_reset(DnfContext * context, const char ** module_specs, GError ** error) try
+{
+ return context_modules_reset_or_disable(context, module_specs, error, true);
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_context_module_switched_check(DnfContext * context, GError ** error) try
+{
+ DnfContextPrivate *priv = GET_PRIVATE (context);
+ if (priv->sack == nullptr) {
+ return TRUE;
+ }
+ auto container = dnf_sack_get_module_container(priv->sack);
+ if (!container) {
+ return TRUE;
+ }
+ auto switched = container->getSwitchedStreams();
+ if (switched.empty()) {
+ return TRUE;
+ }
+ auto logger(libdnf::Log::getLogger());
+ const char * msg = _("The operation would result in switching of module '%s' stream '%s' to stream '%s'");
+ for (auto item : switched) {
+ logger->warning(tfm::format(msg, item.first.c_str(), item.second.first.c_str(), item.second.second.c_str()));
+ }
+ const char * msg_error = _("It is not possible to switch enabled streams of a module.\n"
+ "It is recommended to remove all installed content from the module, and "
+ "reset the module using 'microdnf module reset <module_name>' command. After "
+ "you reset the module, you can install the other stream.");
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, msg_error);
+ return FALSE;
+} CATCH_TO_GERROR(FALSE)
+
+namespace libdnf {
+
+std::map<std::string, std::string> &
+dnf_context_get_vars(DnfContext * context)
+{
+ return *GET_PRIVATE(context)->vars;
+}
+
+bool
+dnf_context_get_vars_cached(DnfContext * context)
+{
+ return GET_PRIVATE(context)->varsCached;
+}
+
+void
+dnf_context_load_vars(DnfContext * context)
+{
+ auto priv = GET_PRIVATE(context);
+ priv->vars->clear();
+ for (auto dir = dnf_context_get_vars_dir(context); *dir; ++dir)
+ ConfigMain::addVarsFromDir(*priv->vars, std::string(priv->install_root) + *dir);
+ ConfigMain::addVarsFromEnv(*priv->vars);
+ priv->varsCached = true;
+}
+
+/* Context part of libdnf (microdnf, packagekit) needs to support global configuration
+ * because of options such as best, zchunk.. This static std::unique_ptr is a hacky way
+ * to do it without touching packagekit.
+ */
+static std::unique_ptr<libdnf::ConfigMain> globalMainConfig;
+static std::mutex getGlobalMainConfigMutex;
+static std::atomic_flag cfgMainLoaded = ATOMIC_FLAG_INIT;
+
+static std::vector<Setopt> globalSetopts;
+static bool globalSetoptsInSync = true;
+
+bool
+addSetopt(const char * key, Option::Priority priority, const char * value, GError ** error)
+{
+ auto dot = strrchr(key, '.');
+ if (dot && *(dot+1) == '\0') {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_UNKNOWN_OPTION, "Last key character cannot be '.': %s", key);
+ return false;
+ }
+
+ // Store option to vector. Use it later when configuration will be loaded.
+ globalSetopts.push_back({static_cast<libdnf::Option::Priority>(priority), key, value});
+ globalSetoptsInSync = false;
+
+ return true;
+}
+
+const std::vector<Setopt> &
+getGlobalSetopts()
+{
+ return globalSetopts;
+}
+
+static void
+dnf_main_conf_apply_setopts()
+{
+ if (globalSetoptsInSync) {
+ return;
+ }
+
+ // apply global main setopts
+ auto & optBinds = globalMainConfig->optBinds();
+ for (const auto & setopt : globalSetopts) {
+ if (setopt.key.find('.') == std::string::npos) {
+ try {
+ auto & optionItem = optBinds.at(setopt.key);
+ try {
+ optionItem.newString(setopt.priority, setopt.value);
+ } catch (const std::exception & ex) {
+ g_warning("dnf_main_conf_apply_setopt: Invalid configuration value: %s = %s; %s", setopt.key.c_str(), setopt.value.c_str(), ex.what());
+ }
+ } catch (const std::exception &) {
+ g_warning("dnf_main_conf_apply_setopt: Unknown configuration option: %s in %s = %s", setopt.key.c_str(), setopt.key.c_str(), setopt.value.c_str());
+ }
+ }
+ }
+
+ globalSetoptsInSync = true;
+}
+
+libdnf::ConfigMain & getGlobalMainConfig(bool canReadConfigFile)
+{
+ std::lock_guard<std::mutex> guard(getGlobalMainConfigMutex);
+
+ if (!globalMainConfig) {
+ globalMainConfig.reset(new libdnf::ConfigMain);
+ // The gpgcheck was enabled by default in context part of libdnf. We stay "compatible".
+ globalMainConfig->gpgcheck().set(libdnf::Option::Priority::DEFAULT, true);
+ }
+
+ if (canReadConfigFile && !cfgMainLoaded.test_and_set()) {
+ if (configFilePath) {
+ globalMainConfig->config_file_path().set(libdnf::Option::Priority::RUNTIME, *configFilePath);
+ if (configFilePath->empty()) {
+ return *globalMainConfig;
+ }
+ }
+
+ libdnf::ConfigParser parser;
+ const std::string cfgPath{globalMainConfig->config_file_path().getValue()};
+ try {
+ parser.read(cfgPath);
+ const auto & cfgParserData = parser.getData();
+ auto cfgParserDataIter = cfgParserData.find("main");
+ if (cfgParserDataIter != cfgParserData.end()) {
+ auto optBinds = globalMainConfig->optBinds();
+ const auto & cfgParserMainSect = cfgParserDataIter->second;
+ for (const auto & opt : cfgParserMainSect) {
+ auto optBindsIter = optBinds.find(opt.first);
+ if (optBindsIter != optBinds.end()) {
+ try {
+ optBindsIter->second.newString(libdnf::Option::Priority::MAINCONFIG, opt.second);
+ } catch (const std::exception & ex) {
+ g_warning("Config error in file \"%s\" section \"main\" key \"%s\": %s",
+ cfgPath.c_str(), opt.first.c_str(), ex.what());
+ }
+ }
+ }
+ }
+ } catch (const libdnf::ConfigParser::CantOpenFile & ex) {
+ if (configFilePath) {
+ // Only warning is logged. But error is reported to the caller during loading
+ // repos (in dnf_repo_loader_refresh()).
+ g_warning("Loading \"%s\": %s", cfgPath.c_str(), ex.what());
+ }
+ } catch (const std::exception & ex) {
+ g_warning("Loading \"%s\": %s", cfgPath.c_str(), ex.what());
+ }
+ }
+
+ dnf_main_conf_apply_setopts();
+ return *globalMainConfig;
+}
+
+}
+
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_CONTEXT_H
+#define __DNF_CONTEXT_H
+
+#include "dnf-types.h"
+#include "plugin/plugin.h"
+
+#ifndef __GI_SCANNER__
+#include "dnf-transaction.h"
+#include "dnf-sack.h"
+#endif
+
+#include <stdbool.h>
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_CONTEXT (dnf_context_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfContext, dnf_context, DNF, CONTEXT, GObject)
+
+struct _DnfContextClass
+{
+ GObjectClass parent_class;
+ void (*invalidate) (DnfContext *context,
+ const gchar *message);
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+/**
+ * DnfContextCleanFlags:
+ * @DNF_CONTEXT_CLEAN_EXPIRE_CACHE: Clean the indicator file for cache directories' age
+ * @DNF_CONTEXT_CLEAN_PACKAGES: Clean the packages section for cache
+ * @DNF_CONTEXT_CLEAN_METADATA: Clean the metadata section for cache directories
+ * @DNF_CONTEXT_CLEAN_ALL: Clean out all of the cache directories
+ *
+ * The clean flags for cache directories cleaning.
+ **/
+typedef enum {
+ DNF_CONTEXT_CLEAN_EXPIRE_CACHE = (1 << 0),
+ DNF_CONTEXT_CLEAN_PACKAGES = (1 << 1),
+ DNF_CONTEXT_CLEAN_METADATA = (1 << 2),
+ DNF_CONTEXT_CLEAN_ALL = (1 << 3),
+} DnfContextCleanFlags;
+
+/**
+ * DnfContextInvalidateFlags:
+ * @DNF_CONTEXT_INVALIDATE_FLAG_NONE: No caches are invalid
+ * @DNF_CONTEXT_INVALIDATE_FLAG_RPMDB: The rpmdb cache is invalid
+ * @DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT: Any enrollment may be invalid
+ *
+ * The update flags.
+ **/
+typedef enum {
+ DNF_CONTEXT_INVALIDATE_FLAG_NONE = 0,
+ DNF_CONTEXT_INVALIDATE_FLAG_RPMDB = 1,
+ DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT = 2,
+ /*< private >*/
+ DNF_CONTEXT_INVALIDATE_FLAG_LAST
+} DnfContextInvalidateFlags;
+
+/**
+ * DnfContextSetupSackFlags:
+ * @DNF_CONTEXT_SETUP_SACK_FLAG_NONE: No special behaviours
+ * @DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_RPMDB: Don't load system's rpmdb
+ * @DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_FILELISTS: Don't load filelists
+ * @DNF_CONTEXT_SETUP_SACK_FLAG_LOAD_UPDATEINFO: Load updateinfo if available
+ *
+ * The sack setup flags.
+ *
+ * Since: 0.13.0
+ **/
+typedef enum {
+ DNF_CONTEXT_SETUP_SACK_FLAG_NONE = (1 << 0),
+ DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_RPMDB = (1 << 1),
+ DNF_CONTEXT_SETUP_SACK_FLAG_SKIP_FILELISTS = (1 << 2),
+ DNF_CONTEXT_SETUP_SACK_FLAG_LOAD_UPDATEINFO = (1 << 3),
+} DnfContextSetupSackFlags;
+
+gboolean dnf_context_globals_init (GError **error);
+
+DnfContext *dnf_context_new (void);
+
+/* utils */
+const gchar *find_base_arch (const char *native);
+
+/* getters */
+const gchar *dnf_context_get_config_file_path (void);
+gboolean dnf_context_is_set_config_file_path (void);
+const gchar * const *dnf_context_get_repos_dir (DnfContext *context);
+const gchar *dnf_context_get_repo_dir (DnfContext *context);
+const gchar * const *dnf_context_get_vars_dir (DnfContext *context);
+const gchar *dnf_context_get_base_arch (DnfContext *context);
+const gchar *dnf_context_get_os_info (DnfContext *context);
+const gchar *dnf_context_get_arch_info (DnfContext *context);
+const gchar *dnf_context_get_release_ver (DnfContext *context);
+const gchar *dnf_context_get_platform_module (DnfContext *context);
+const gchar *dnf_context_get_cache_dir (DnfContext *context);
+const gchar *dnf_context_get_arch (DnfContext *context);
+const gchar *dnf_context_get_solv_dir (DnfContext *context);
+const gchar *dnf_context_get_lock_dir (DnfContext *context);
+const gchar *dnf_context_get_rpm_verbosity (DnfContext *context);
+const gchar *dnf_context_get_install_root (DnfContext *context);
+const gchar *dnf_context_get_source_root (DnfContext *context);
+const gchar **dnf_context_get_native_arches (DnfContext *context);
+const gchar **dnf_context_get_installonly_pkgs (DnfContext *context);
+gboolean dnf_context_get_best (void);
+gboolean dnf_context_get_install_weak_deps (void);
+gboolean dnf_context_get_allow_vendor_change (void);
+gboolean dnf_context_get_cache_only (DnfContext *context);
+gboolean dnf_context_get_check_disk_space (DnfContext *context);
+gboolean dnf_context_get_check_transaction (DnfContext *context);
+gboolean dnf_context_get_keep_cache (DnfContext *context);
+gboolean dnf_context_get_only_trusted (DnfContext *context);
+gboolean dnf_context_get_zchunk (DnfContext *context);
+gboolean dnf_context_get_write_history (DnfContext *context);
+guint dnf_context_get_cache_age (DnfContext *context);
+guint dnf_context_get_installonly_limit (DnfContext *context);
+const gchar *dnf_context_get_http_proxy (DnfContext *context);
+gboolean dnf_context_get_enable_filelists (DnfContext *context);
+GPtrArray *dnf_context_get_repos (DnfContext *context);
+#ifndef __GI_SCANNER__
+DnfRepoLoader *dnf_context_get_repo_loader (DnfContext *context);
+DnfTransaction *dnf_context_get_transaction (DnfContext *context);
+DnfSack *dnf_context_get_sack (DnfContext *context);
+HyGoal dnf_context_get_goal (DnfContext *context);
+#endif
+DnfState* dnf_context_get_state (DnfContext *context);
+const char * dnf_context_get_user_agent (DnfContext *context);
+
+/* setters */
+void dnf_context_set_config_file_path (const gchar *config_file_path);
+void dnf_context_set_repos_dir (DnfContext *context,
+ const gchar * const *repos_dir);
+void dnf_context_set_repo_dir (DnfContext *context,
+ const gchar *repo_dir);
+void dnf_context_set_vars_dir (DnfContext *context,
+ const gchar * const *vars_dir);
+void dnf_context_set_release_ver (DnfContext *context,
+ const gchar *release_ver);
+void dnf_context_set_platform_module (DnfContext *context,
+ const gchar *platform_module);
+void dnf_context_set_cache_dir (DnfContext *context,
+ const gchar *cache_dir);
+void dnf_context_set_arch (DnfContext *context,
+ const gchar *base_arch);
+void dnf_context_set_solv_dir (DnfContext *context,
+ const gchar *solv_dir);
+void dnf_context_set_vendor_cache_dir (DnfContext *context,
+ const gchar *vendor_cache_dir);
+void dnf_context_set_vendor_solv_dir (DnfContext *context,
+ const gchar *vendor_solv_dir);
+void dnf_context_set_lock_dir (DnfContext *context,
+ const gchar *lock_dir);
+void dnf_context_set_rpm_verbosity (DnfContext *context,
+ const gchar *rpm_verbosity);
+void dnf_context_set_install_root (DnfContext *context,
+ const gchar *install_root);
+void dnf_context_set_source_root (DnfContext *context,
+ const gchar *source_root);
+void dnf_context_set_best (gboolean best);
+void dnf_context_set_install_weak_deps (gboolean enabled);
+void dnf_context_set_allow_vendor_change (gboolean vendorchange);
+void dnf_context_set_cache_only (DnfContext *context,
+ gboolean cache_only);
+void dnf_context_set_check_disk_space (DnfContext *context,
+ gboolean check_disk_space);
+void dnf_context_set_check_transaction (DnfContext *context,
+ gboolean check_transaction);
+void dnf_context_set_keep_cache (DnfContext *context,
+ gboolean keep_cache);
+void dnf_context_set_enable_filelists (DnfContext *context,
+ gboolean enable_filelists);
+void dnf_context_set_only_trusted (DnfContext *context,
+ gboolean only_trusted);
+void dnf_context_set_zchunk (DnfContext *context,
+ gboolean only_trusted);
+void dnf_context_set_write_history (DnfContext *context,
+ gboolean value);
+void dnf_context_set_cache_age (DnfContext *context,
+ guint cache_age);
+
+void dnf_context_set_rpm_macro (DnfContext *context,
+ const gchar *key,
+ const gchar *value);
+void dnf_context_set_http_proxy (DnfContext *context,
+ const gchar *proxyurl);
+void dnf_context_set_user_agent (DnfContext *context,
+ const gchar *user_agent);
+
+/* object methods */
+gboolean dnf_context_setup (DnfContext *context,
+ GCancellable *cancellable,
+ GError **error);
+gboolean dnf_context_setup_enrollments (DnfContext *context,
+ GError **error);
+gboolean dnf_context_setup_sack (DnfContext *context,
+ DnfState *state,
+ GError **error);
+gboolean dnf_context_setup_sack_with_flags (DnfContext *context,
+ DnfState *state,
+ DnfContextSetupSackFlags flags,
+ GError **error);
+gboolean dnf_context_commit (DnfContext *context,
+ DnfState *state,
+ GError **error);
+void dnf_context_invalidate (DnfContext *context,
+ const gchar *message);
+void dnf_context_invalidate_full (DnfContext *context,
+ const gchar *message,
+ DnfContextInvalidateFlags flags);
+gboolean dnf_context_clean_cache (DnfContext *context,
+ DnfContextCleanFlags flags,
+ GError **error);
+gboolean dnf_context_install (DnfContext *context,
+ const gchar *name,
+ GError **error);
+gboolean dnf_context_remove (DnfContext *context,
+ const gchar *name,
+ GError **error);
+gboolean dnf_context_update (DnfContext *context,
+ const gchar *name,
+ GError **error);
+gboolean dnf_context_update_all (DnfContext *context,
+ GError **error);
+gboolean dnf_context_distrosync (DnfContext *context,
+ const gchar *name,
+ GError **error);
+gboolean dnf_context_distrosync_all (DnfContext *context,
+ GError **error);
+gboolean dnf_context_repo_enable (DnfContext *context,
+ const gchar *repo_id,
+ GError **error);
+gboolean dnf_context_repo_disable (DnfContext *context,
+ const gchar *repo_id,
+ GError **error);
+gboolean dnf_context_run (DnfContext *context,
+ GCancellable *cancellable,
+ GError **error);
+
+/* plugins support */
+void dnf_context_disable_plugins (const gchar *plugin_name_pattern);
+void dnf_context_enable_plugins (const gchar *plugin_name_pattern);
+gchar** dnf_context_get_disabled_plugins (void);
+gchar** dnf_context_get_enabled_plugins (void);
+gboolean dnf_context_get_plugins_all_disabled (void);
+void dnf_context_set_plugins_all_disabled (gboolean disabled);
+const char * dnf_context_get_plugins_dir (DnfContext *context);
+void dnf_context_set_plugins_dir (DnfContext *context,
+ const char *plugins_dir);
+bool dnf_context_plugin_hook (DnfContext *context,
+ PluginHookId id,
+ DnfPluginHookData *hookData,
+ DnfPluginError *error);
+/// String must be dealocated by g_free()
+gchar * dnf_context_get_module_report (DnfContext * context);
+
+/**
+ * dnf_context_reset_modules:
+ * @context: DnfContext
+ * @sack: DnfSack
+ * @module_names: Names of modules to reset
+ * @error: Error
+ *
+ * Reset modules, commit modular changes, and recalculate module filtration.
+ * Note you likely want to use dnf_context_module_reset instead which matches
+ * the behaviour of other modular APIs to not commit modular changes to disk
+ * until dnf_context_run(). Returns FALSE when an error is set.
+ *
+ * Since: 0.38.1
+ **/
+gboolean dnf_context_reset_modules (DnfContext * context,
+ DnfSack * sack,
+ const char ** module_names,
+ GError ** error);
+
+/**
+ * dnf_context_reset_all_modules:
+ * @context: DnfContext
+ * @sack: DnfSack
+ * @error: Error
+ *
+ * Reset all modules and recalculate module filtration.
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.46.2
+ **/
+gboolean dnf_context_reset_all_modules (DnfContext * context,
+ DnfSack * sack,
+ GError ** error);
+
+/**
+ * dnf_context_module_enable:
+ * @context: DnfContext
+ * @module_specs: Module specs that should be enabled
+ * @error: Error
+ *
+ * Enable modules, recalculate module filtration, but do not commit modular changes.
+ * To commit modular changes, call dnf_context_run().
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.55.0
+ **/
+gboolean dnf_context_module_enable (DnfContext * context,
+ const char ** module_specs,
+ GError ** error);
+
+/**
+ * dnf_context_module_install:
+ * @context: DnfContext
+ * @module_specs: Module specs that should be installed
+ * @error: Error
+ *
+ * Enable modules and mark for installation but do not commit modular changes.
+ * To commit modular changes, call dnf_context_run().
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.63.0
+ **/
+gboolean dnf_context_module_install (DnfContext * context,
+ const char ** module_specs,
+ GError ** error);
+
+/**
+ * dnf_context_module_disable:
+ * @context: DnfContext
+ * @module_specs: Module specs that should be enabled
+ * @error: Error
+ *
+ * Disable modules, recalculate module filtration, but do not commit modular changes.
+ * To commit modular changes it requires to call dnf_context_run()
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.55.0
+ **/
+gboolean dnf_context_module_disable (DnfContext * context,
+ const char ** module_specs,
+ GError ** error);
+
+/**
+ * dnf_context_module_disable_all:
+ * @context: DnfContext
+ * @module_specs: Module specs that should be enabled
+ * @error: Error
+ *
+ * Disable all modules, recalculate module filtration, but do not commit modular
+ * changes. To commit modular changes it requires to call dnf_context_run()
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.64.0
+ **/
+gboolean dnf_context_module_disable_all (DnfContext * context,
+ GError ** error);
+
+/**
+ * dnf_context_module_reset:
+ * @context: DnfContext
+ * @module_specs: Module specs that should be enabled
+ * @error: Error
+ *
+ * Reset modules, recalculate module filtration, but do not commit modular changes.
+ * To commit modular changes it requires to call dnf_context_run()
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.55.0
+ **/
+gboolean dnf_context_module_reset (DnfContext * context,
+ const char ** module_specs,
+ GError ** error);
+/**
+ * dnf_context_module_switched_check:
+ * @context: DnfContext
+ * @error: Error
+ *
+ * Ceck if any module is switched and return FALSE and sets an error
+ * Returns FALSE when an error is set.
+ *
+ * Since: 0.55.0
+ **/
+gboolean dnf_context_module_switched_check (DnfContext * context,
+ GError ** error);
+
+G_END_DECLS
+
+#endif /* __DNF_CONTEXT_H */
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_CONTEXT_HPP
+#define __DNF_CONTEXT_HPP
+
+#include "dnf-context.h"
+#include "conf/ConfigMain.hpp"
+
+#include <map>
+#include <string>
+
+
+inline DnfContextInvalidateFlags operator|(DnfContextInvalidateFlags a, DnfContextInvalidateFlags b)
+{
+ return static_cast<DnfContextInvalidateFlags>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+namespace libdnf {
+
+struct Setopt {
+ Option::Priority priority;
+ std::string key;
+ std::string value;
+};
+
+std::map<std::string, std::string> & dnf_context_get_vars(DnfContext * context);
+bool dnf_context_get_vars_cached(DnfContext * context);
+void dnf_context_load_vars(DnfContext * context);
+ConfigMain & getGlobalMainConfig(bool canReadConfigFile = true);
+bool addSetopt(const char * key, Option::Priority priority, const char * value, GError ** error);
+const std::vector<Setopt> & getGlobalSetopts();
+
+}
+
+#endif /* __DNF_CONTEXT_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <glib.h>
+
+#include "dnf-db.h"
+#include "dnf-package.h"
+#include "transaction/Swdb.hpp"
+
+/**
+ * dnf_db_ensure_origin_pkg:
+ * @db: a #DnfDb instance.
+ * @pkg: A package to set
+ *
+ * Sets the repo origin on a package if not already set.
+ *
+ * Since: 0.1.0
+ */
+void
+dnf_db_ensure_origin_pkg(DnfDb *db, DnfPackage *pkg)
+{
+ /* already set */
+ if (dnf_package_get_origin(pkg) != NULL)
+ return;
+ if (!dnf_package_installed(pkg))
+ return;
+
+ /* set from the database if available */
+ auto tmp = db->getRPMRepo(dnf_package_get_nevra(pkg));
+ if (tmp.empty()) {
+ g_debug("no origin for %s", dnf_package_get_package_id(pkg));
+ } else {
+ dnf_package_set_origin(pkg, tmp.c_str());
+ }
+}
+
+/**
+ * dnf_db_ensure_origin_pkglist:
+ * @db: a #DnfDb instance.
+ * @pkglist: A package list to set
+ *
+ * Sets the repo origin on several package if not already set.
+ *
+ * Since: 0.1.0
+ */
+void
+dnf_db_ensure_origin_pkglist(DnfDb *db, GPtrArray *pkglist)
+{
+ DnfPackage * pkg;
+ guint i;
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index(pkglist, i));
+ dnf_db_ensure_origin_pkg(db, pkg);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_DB_H
+#define __DNF_DB_H
+
+#include "dnf-context.h"
+#include "dnf-types.h"
+#include "hy-package.h"
+
+#include <glib/garray.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void dnf_db_ensure_origin_pkg(DnfDb * db, DnfPackage * pkg);
+void dnf_db_ensure_origin_pkglist(DnfDb * db, GPtrArray * pkglist);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_DB_H */
--- /dev/null
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * DnfComparisonKind:
+ *
+ * The comparison type.
+ */
+typedef enum
+{
+ DNF_COMPARISON_ICASE = 1 << 0,
+ DNF_COMPARISON_NOT = 1 << 1,
+ DNF_COMPARISON_FLAG_MASK = DNF_COMPARISON_ICASE | DNF_COMPARISON_NOT, /*< private >*/
+
+ DNF_COMPARISON_EQ = 1 << 8,
+ DNF_COMPARISON_LT = 1 << 9,
+ DNF_COMPARISON_GT = 1 << 10,
+
+ DNF_COMPARISON_SUBSTR = 1 << 11,
+ DNF_COMPARISON_GLOB = 1 << 12,
+
+ DNF_COMPARISON_NEQ = DNF_COMPARISON_EQ | DNF_COMPARISON_NOT,
+
+ DNF_COMPARISON_NAME_ONLY = 1 << 16,
+} DnfComparisonKind;
+
+G_END_DECLS
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Most of this code was taken from Zif, libzif/zif-transaction.c
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-goal
+ * @short_description: Helper methods for dealing with hawkey goals.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * These methods make it easier to deal with hawkey goals.
+ */
+
+
+#include <glib.h>
+
+#include "catch-error.hpp"
+#include "hy-util.h"
+#include "hy-goal-private.hpp"
+#include "dnf-goal.h"
+#include "dnf-package.h"
+#include "hy-packageset-private.hpp"
+#include "hy-iutil-private.hpp"
+#include "dnf-context.hpp"
+#include "dnf-sack-private.hpp"
+#include "dnf-utils.h"
+#include "utils/bgettext/bgettext-lib.h"
+#include "../goal/Goal.hpp"
+
+#include <vector>
+
+static void set_excludes_from_weak_to_goal(HyGoal goal)
+{
+ DnfSack * sack = hy_goal_get_sack(goal);
+
+ goal->reset_exclude_from_weak();
+
+ const auto & exclude_from_weak_autodetect = libdnf::getGlobalMainConfig().exclude_from_weak_autodetect().getValue();
+ if (exclude_from_weak_autodetect) {
+ goal->exclude_from_weak_autodetect();
+ }
+
+ const auto & exclude_from_weak = libdnf::getGlobalMainConfig().exclude_from_weak().getValue();
+
+ for (auto & exclude : exclude_from_weak) {
+ libdnf::Query query(sack);
+ auto ret = query.filterSubject(exclude.c_str(), nullptr, false, true, false, false);
+ goal->add_exclude_from_weak(*query.getResultPset());
+ }
+}
+
+/**
+ * dnf_goal_depsolve:
+ * @goal: a #HyGoal.
+ * @flags: some #DnfGoalActions to enable.
+ * @error: a #GError or %NULL
+ *
+ * Returns: %TRUE if depsolve is successful.
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_goal_depsolve(HyGoal goal, DnfGoalActions flags, GError **error) try
+{
+ gint cnt;
+ gint j;
+ gint rc;
+ g_autoptr(GString) string = NULL;
+
+ DnfSack * sack = hy_goal_get_sack(goal);
+
+ libdnf::Query query(sack);
+ const auto & protected_packages = libdnf::getGlobalMainConfig().protected_packages().getValue();
+ std::vector<const char *> cprotected_packages;
+ cprotected_packages.reserve(protected_packages.size() + 1);
+ for (const auto & package : protected_packages) {
+ cprotected_packages.push_back(package.c_str());
+ }
+ cprotected_packages.push_back(nullptr);
+ query.addFilter(HY_PKG_NAME, HY_EQ, cprotected_packages.data());
+ auto pkgset = *query.runSet();
+ goal->addProtected(pkgset);
+
+ set_excludes_from_weak_to_goal(goal);
+
+ rc = hy_goal_run_flags(goal, flags);
+ if (rc) {
+ string = g_string_new(_("Could not depsolve transaction; "));
+ cnt = hy_goal_count_problems(goal);
+ g_string_append_printf(string, P_("%i problem detected:\n", "%i problems detected:\n", cnt),
+ cnt);
+ for (j = 0; j < cnt; j++) {
+ auto tmp = goal->describeProblemRules(j, true);
+ bool first = true;
+ for (auto & iter: tmp) {
+ if (first) {
+ if (cnt != 1) {
+ g_string_append_printf(string, _(" Problem %1$i: %2$s\n"), j + 1, iter.c_str());
+ } else {
+ g_string_append_printf(string, _(" Problem: %s\n"), iter.c_str());
+ }
+ first = false;
+ } else {
+ g_string_append_printf(string, " - %s\n", iter.c_str());
+ }
+ }
+ }
+ g_string_truncate(string, string->len - 1);
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_PACKAGE_CONFLICTS,
+ string->str);
+ return FALSE;
+ }
+
+ /* anything to do? */
+ if (hy_goal_req_length(goal) == 0) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_NO_PACKAGES_TO_UPDATE,
+ "The transaction was empty");
+ return FALSE;
+ }
+ auto moduleContainer = dnf_sack_get_module_container(sack);
+ if (moduleContainer) {
+ auto installSet = goal->listInstalls();
+ auto modulesToEnable = requiresModuleEnablement(sack, &installSet);
+ for (auto module: modulesToEnable) {
+ moduleContainer->enable(module->getName(), module->getStream());
+ }
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_goal_get_packages:
+ */
+GPtrArray *
+dnf_goal_get_packages(HyGoal goal, ...)
+{
+ GPtrArray *array;
+ DnfPackage *pkg;
+ gint info_tmp;
+ guint i;
+ guint j;
+ va_list args;
+
+ /* process the valist */
+ va_start(args, goal);
+ array = g_ptr_array_new_with_free_func((GDestroyNotify) g_object_unref);
+ for (j = 0;; j++) {
+ GPtrArray *pkglist = NULL;
+ info_tmp = va_arg(args, gint);
+ if (info_tmp == -1)
+ break;
+ switch(info_tmp) {
+ case DNF_PACKAGE_INFO_REMOVE:
+ pkglist = hy_goal_list_erasures(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_REMOVE);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ case DNF_PACKAGE_INFO_INSTALL:
+ pkglist = hy_goal_list_installs(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_INSTALL);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ case DNF_PACKAGE_INFO_OBSOLETE:
+ pkglist = hy_goal_list_obsoleted(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_OBSOLETE);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ case DNF_PACKAGE_INFO_REINSTALL:
+ pkglist = hy_goal_list_reinstalls(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_REINSTALL);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ case DNF_PACKAGE_INFO_UPDATE:
+ pkglist = hy_goal_list_upgrades(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_UPDATE);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ case DNF_PACKAGE_INFO_DOWNGRADE:
+ pkglist = hy_goal_list_downgrades(goal, NULL);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg = (DnfPackage*)g_ptr_array_index (pkglist, i);
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_DOWNGRADE);
+ g_ptr_array_add(array, g_object_ref(pkg));
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_ptr_array_unref(pkglist);
+ }
+ va_end(args);
+ return array;
+}
+
+/**
+ * dnf_goal_add_protected:
+ * @goal: a #HyGoal.
+ * @pset: a #DnfPackageSet that would be added to the protected packages.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_goal_add_protected(HyGoal goal, DnfPackageSet *pset)
+{
+ goal->addProtected(*pset);
+}
+
+/**
+ * dnf_goal_set_protected:
+ * @goal: a #HyGoal.
+ * @pset: a #DnfPackageSet of protected packages (the previous setup will be overridden).
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_goal_set_protected(HyGoal goal, DnfPackageSet *pset)
+{
+ goal->setProtected(*pset);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_GOAL_H
+#define __DNF_GOAL_H
+
+#include <glib.h>
+
+#include "hy-goal.h"
+#include "hy-package.h"
+
+G_BEGIN_DECLS
+
+gboolean dnf_goal_depsolve (HyGoal goal,
+ DnfGoalActions flags,
+ GError **error);
+GPtrArray *dnf_goal_get_packages (HyGoal goal,
+ ...);
+void dnf_goal_add_protected (HyGoal goal,
+ DnfPackageSet *pset);
+void dnf_goal_set_protected (HyGoal goal,
+ DnfPackageSet *pset);
+
+G_END_DECLS
+
+#endif /* __DNF_GOAL_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Most of this code was taken from Zif, libzif/zif-transaction.c
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/**
+ * SECTION:dnf-keyring
+ * @short_description: Helper methods for dealing with rpm keyrings.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * These methods make it easier to deal with rpm keyrings.
+ */
+
+
+#include <stdlib.h>
+#include <glib.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmcli.h>
+
+#include "catch-error.hpp"
+#include "dnf-types.h"
+#include "dnf-keyring.h"
+#include "dnf-utils.h"
+
+/**
+ * dnf_keyring_add_public_key:
+ * @keyring: a #rpmKeyring instance.
+ * @filename: The public key filename.
+ * @error: a #GError or %NULL.
+ *
+ * Adds a specific public key to the keyring.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_keyring_add_public_key(rpmKeyring keyring,
+ const gchar *filename,
+ GError **error) try
+{
+ gboolean ret = TRUE;
+ int rc;
+ gsize len;
+ pgpArmor armor;
+ rpmPubkey pubkey = NULL;
+ rpmPubkey *subkeys = NULL;
+ int nsubkeys = 0;
+ uint8_t *pkt = NULL;
+ g_autofree gchar *data = NULL;
+
+ /* ignore symlinks and directories */
+ if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
+ goto out;
+ if (g_file_test(filename, G_FILE_TEST_IS_SYMLINK))
+ goto out;
+
+ /* get data */
+ ret = g_file_get_contents(filename, &data, &len, error);
+ if (!ret)
+ goto out;
+
+ /* rip off the ASCII armor and parse it */
+ armor = pgpParsePkts(data, &pkt, &len);
+ if (armor < 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "failed to parse PKI file %s",
+ filename);
+ goto out;
+ }
+
+ /* make sure it's something we can add to rpm */
+ if (armor != PGPARMOR_PUBKEY) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "PKI file %s is not a public key",
+ filename);
+ goto out;
+ }
+
+ /* test each one */
+ pubkey = rpmPubkeyNew(pkt, len);
+ if (pubkey == NULL) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "failed to parse public key for %s",
+ filename);
+ goto out;
+ }
+
+ /* add to in-memory keyring */
+ rc = rpmKeyringAddKey(keyring, pubkey);
+ if (rc == 1) {
+ ret = TRUE;
+ g_debug("%s is already added", filename);
+ goto out;
+ } else if (rc < 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "failed to add public key %s to rpmdb",
+ filename);
+ goto out;
+ }
+
+ subkeys = rpmGetSubkeys(pubkey, &nsubkeys);
+ for (int i = 0; i < nsubkeys; i++) {
+ rpmPubkey subkey = subkeys[i];
+ if (rpmKeyringAddKey(keyring, subkey) < 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "failed to add subkeys for %s to rpmdb",
+ filename);
+ goto out;
+ }
+ }
+
+ /* success */
+ g_debug("added missing public key %s to rpmdb", filename);
+ ret = TRUE;
+out:
+ if (pkt != NULL)
+ free(pkt); /* yes, free() */
+ if (pubkey != NULL)
+ rpmPubkeyFree(pubkey);
+ if (subkeys != NULL) {
+ for (int i = 0; i < nsubkeys; i++) {
+ rpmPubkeyFree(subkeys[i]);
+ }
+ free(subkeys);
+ }
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_keyring_add_public_keys:
+ * @keyring: a #rpmKeyring instance.
+ * @error: a #GError or %NULL.
+ *
+ * Adds all installed public keys to the RPM and shared keyring.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try
+{
+ const gchar *gpg_dir = "/etc/pki/rpm-gpg";
+ gboolean ret = TRUE;
+ g_autoptr(GDir) dir = NULL;
+ GError *localError = NULL;
+
+ /* search all the public key files */
+ dir = g_dir_open(gpg_dir, 0, &localError);
+ if (dir == NULL) {
+ if (localError->domain != G_FILE_ERROR || localError->code != G_FILE_ERROR_NOENT) {
+ g_warning("%s", localError->message);
+ }
+ g_error_free(localError);
+ return TRUE;
+ }
+ do {
+ const gchar *filename;
+ g_autofree gchar *path_tmp = NULL;
+ filename = g_dir_read_name(dir);
+ if (filename == NULL)
+ break;
+ path_tmp = g_build_filename(gpg_dir, filename, NULL);
+ ret = dnf_keyring_add_public_key(keyring, path_tmp, &localError);
+ if (!ret) {
+ g_warning("%s", localError->message);
+ g_error_free(localError);
+ localError = NULL;
+ }
+ } while (true);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+static int
+rpmcliverifysignatures_log_handler_cb(rpmlogRec rec, rpmlogCallbackData data)
+{
+ GString **string =(GString **) data;
+
+ /* create string if required */
+ if (*string == NULL)
+ *string = g_string_new("");
+
+ /* if text already exists, join them */
+ if ((*string)->len > 0)
+ g_string_append(*string, ": ");
+ g_string_append(*string, rpmlogRecMessage(rec));
+
+ /* remove the trailing /n which rpm does */
+ if ((*string)->len > 0)
+ g_string_truncate(*string,(*string)->len - 1);
+ return 0;
+}
+
+/**
+ * dnf_keyring_check_untrusted_file:
+ */
+gboolean
+dnf_keyring_check_untrusted_file(rpmKeyring keyring,
+ const gchar *filename,
+ GError **error) try
+{
+ FD_t fd = NULL;
+ gboolean ret = FALSE;
+ Header hdr = NULL;
+ rpmRC rc;
+ rpmts ts = NULL;
+
+ char *path = g_strdup(filename);
+ char *path_array[2] = {path, NULL};
+ g_autoptr(GString) rpm_error = NULL;
+
+ /* open the file for reading */
+ fd = Fopen(filename, "r.fdio");
+ if (fd == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ "failed to open %s",
+ filename);
+ goto out;
+ }
+ if (Ferror(fd)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ "failed to open %s: %s",
+ filename,
+ Fstrerror(fd));
+ goto out;
+ }
+
+ ts = rpmtsCreate();
+
+ if (rpmtsSetKeyring(ts, keyring) < 0) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, "failed to set keyring");
+ goto out;
+ }
+ rpmtsSetVfyLevel(ts, RPMSIG_SIGNATURE_TYPE);
+ rpmlogSetCallback(rpmcliverifysignatures_log_handler_cb, &rpm_error);
+
+ // rpm doesn't provide any better API call than rpmcliVerifySignatures (which is for CLI):
+ // - use path_array as input argument
+ // - gather logs via callback because we don't want to print anything if check is successful
+ if (rpmcliVerifySignatures(ts, (char * const*) path_array)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "%s could not be verified.\n%s",
+ filename,
+ (rpm_error ? rpm_error->str : "UNKNOWN ERROR"));
+ goto out;
+ }
+
+ /* read in the file */
+ rc = rpmReadPackageFile(ts, fd, filename, &hdr);
+ if (rc != RPMRC_OK) {
+ /* we only return SHA1 and MD5 failures, as we're not
+ * checking signatures at this stage */
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ "%s could not be verified",
+ filename);
+ goto out;
+ }
+
+ /* the package is signed by a key we trust */
+ g_debug("%s has been verified as trusted", filename);
+ ret = TRUE;
+out:
+ rpmlogSetCallback(NULL, NULL);
+
+ if (path != NULL)
+ g_free(path);
+ if (ts != NULL)
+ rpmtsFree(ts);
+ if (hdr != NULL)
+ headerFree(hdr);
+ if (fd != NULL)
+ Fclose(fd);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_KEYRING_H
+#define __DNF_KEYRING_H
+
+#include <glib.h>
+
+#include <rpm/rpmkeyring.h>
+
+G_BEGIN_DECLS
+
+gboolean dnf_keyring_add_public_key (rpmKeyring keyring,
+ const gchar *filename,
+ GError **error);
+gboolean dnf_keyring_add_public_keys (rpmKeyring keyring,
+ GError **error);
+gboolean dnf_keyring_check_untrusted_file (rpmKeyring keyring,
+ const gchar *filename,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_KEYRING_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2009-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * Most of this code was taken from Zif, libzif/zif-lock.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-lock
+ * @short_description: Lock the package system.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * This object either works per-thread or per-system with a configured lock file.
+ *
+ * See also: #DnfState
+ */
+
+
+#include <gio/gio.h>
+
+#include "catch-error.hpp"
+#include "dnf-lock.h"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+
+typedef struct
+{
+ GMutex mutex;
+ GPtrArray *item_array; /* of DnfLockItem */
+ gchar *lock_dir;
+} DnfLockPrivate;
+
+typedef struct {
+ gpointer owner;
+ guint id;
+ guint refcount;
+ DnfLockMode mode;
+ DnfLockType type;
+} DnfLockItem;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfLock, dnf_lock, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfLockPrivate *>(dnf_lock_get_instance_private (o)))
+
+enum {
+ SIGNAL_STATE_CHANGED,
+ SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+static gpointer dnf_lock_object = NULL;
+
+/**
+ * dnf_lock_finalize:
+ **/
+static void
+dnf_lock_finalize(GObject *object)
+{
+ DnfLock *lock = DNF_LOCK(object);
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ guint i;
+
+ /* unlock if we hold the lock */
+ for (i = 0; i < priv->item_array->len; i++) {
+ auto item = static_cast<DnfLockItem *>(g_ptr_array_index(priv->item_array, i));
+ if (item->refcount > 0) {
+ g_warning("held lock %s at shutdown",
+ dnf_lock_type_to_string(item->type));
+ dnf_lock_release(lock, item->id, NULL);
+ }
+ }
+ g_ptr_array_unref(priv->item_array);
+ g_free(priv->lock_dir);
+
+ G_OBJECT_CLASS(dnf_lock_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_lock_init:
+ **/
+static void
+dnf_lock_init(DnfLock *lock)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ priv->item_array = g_ptr_array_new_with_free_func(g_free);
+ priv->lock_dir = g_strdup("/var/run");
+}
+
+/**
+ * dnf_lock_class_init:
+ **/
+static void
+dnf_lock_class_init(DnfLockClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ signals [SIGNAL_STATE_CHANGED] =
+ g_signal_new("state-changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfLockClass, state_changed),
+ NULL, NULL, g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+
+ object_class->finalize = dnf_lock_finalize;
+}
+
+/**
+ * dnf_lock_type_to_string:
+ * @lock_type: a #DnfLockType.
+ *
+ * Returns: The string representation of the lock type.
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_lock_type_to_string(DnfLockType lock_type)
+{
+ if (lock_type == DNF_LOCK_TYPE_RPMDB)
+ return "rpmdb";
+ if (lock_type == DNF_LOCK_TYPE_REPO)
+ return "src";
+ if (lock_type == DNF_LOCK_TYPE_METADATA)
+ return "metadata";
+ if (lock_type == DNF_LOCK_TYPE_CONFIG)
+ return "config";
+ return "unknown";
+}
+
+/**
+ * dnf_lock_mode_to_string:
+ **/
+static const gchar *
+dnf_lock_mode_to_string(DnfLockMode lock_mode)
+{
+ if (lock_mode == DNF_LOCK_MODE_THREAD)
+ return "thread";
+ if (lock_mode == DNF_LOCK_MODE_PROCESS)
+ return "process";
+ return "unknown";
+}
+
+/**
+ * dnf_lock_get_item_by_type_mode:
+ **/
+static DnfLockItem *
+dnf_lock_get_item_by_type_mode(DnfLock *lock,
+ DnfLockType type,
+ DnfLockMode mode)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ guint i;
+
+ /* search for the item that matches type */
+ for (i = 0; i < priv->item_array->len; i++) {
+ auto item = static_cast<DnfLockItem *>(g_ptr_array_index(priv->item_array, i));
+ if (item->type == type && item->mode == mode)
+ return item;
+ }
+ return NULL;
+}
+
+/**
+ * dnf_lock_get_item_by_id:
+ **/
+static DnfLockItem *
+dnf_lock_get_item_by_id(DnfLock *lock, guint id)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ guint i;
+
+ /* search for the item that matches the ID */
+ for (i = 0; i < priv->item_array->len; i++) {
+ auto item = static_cast<DnfLockItem *>(g_ptr_array_index(priv->item_array, i));
+ if (item->id == id)
+ return item;
+ }
+ return NULL;
+}
+
+/**
+ * dnf_lock_create_item:
+ **/
+static DnfLockItem *
+dnf_lock_create_item(DnfLock *lock, DnfLockType type, DnfLockMode mode)
+{
+ DnfLockItem *item;
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ static guint id = 1;
+
+ item = g_new0(DnfLockItem, 1);
+ item->id = id++;
+ item->type = type;
+ item->owner = g_thread_self();
+ item->refcount = 1;
+ item->mode = mode;
+ g_ptr_array_add(priv->item_array, item);
+ return item;
+}
+
+/**
+ * dnf_lock_get_pid:
+ **/
+static guint
+dnf_lock_get_pid(DnfLock *lock, const gchar *filename, GError **error)
+{
+ gboolean ret;
+ guint64 pid;
+ gchar *endptr = NULL;
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *contents = NULL;
+
+ g_return_val_if_fail(DNF_IS_LOCK(lock), FALSE);
+
+ /* file doesn't exists */
+ ret = g_file_test(filename, G_FILE_TEST_EXISTS);
+ if (!ret) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "lock file not present");
+ return 0;
+ }
+
+ /* get contents */
+ ret = g_file_get_contents(filename, &contents, NULL, &error_local);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "lock file not set: %s",
+ error_local->message);
+ return 0;
+ }
+
+ /* convert to int */
+ pid = g_ascii_strtoull(contents, &endptr, 10);
+
+ /* failed to parse */
+ if (contents == endptr) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ "failed to parse pid: %s", contents);
+ return 0;
+ }
+
+ /* too large */
+ if (pid > G_MAXUINT) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ "pid too large %" G_GUINT64_FORMAT, pid);
+ return 0;
+ }
+ return(guint) pid;
+}
+
+/**
+ * dnf_lock_get_filename_for_type:
+ **/
+static gchar *
+dnf_lock_get_filename_for_type(DnfLock *lock, DnfLockType type)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ return g_strdup_printf("%s/dnf-%s.lock",
+ priv->lock_dir,
+ dnf_lock_type_to_string(type));
+}
+
+/**
+ * dnf_lock_get_cmdline_for_pid:
+ **/
+static gchar *
+dnf_lock_get_cmdline_for_pid(guint pid)
+{
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *data = NULL;
+ g_autofree gchar *filename = NULL;
+
+ /* find the cmdline */
+ filename = g_strdup_printf("/proc/%i/cmdline", pid);
+ ret = g_file_get_contents(filename, &data, NULL, &error);
+ if (ret)
+ return g_strdup_printf("%s(%i)", data, pid);
+ g_warning("failed to get cmdline: %s", error->message);
+ return g_strdup_printf("unknown(%i)", pid);
+}
+
+/**
+ * dnf_lock_set_lock_dir:
+ * @lock: a #DnfLock instance.
+ * @lock_dir: the directory to use for lock files
+ *
+ * Sets the directory to use for lock files.
+ *
+ * Since: 0.1.4
+ **/
+void
+dnf_lock_set_lock_dir(DnfLock *lock, const gchar *lock_dir)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ g_return_if_fail(DNF_IS_LOCK(lock));
+ g_free(priv->lock_dir);
+ priv->lock_dir = g_strdup(lock_dir);
+}
+
+/**
+ * dnf_lock_get_state:
+ * @lock: a #DnfLock instance.
+ *
+ * Gets a bitfield of what locks have been taken
+ *
+ * Returns: A bitfield.
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_lock_get_state(DnfLock *lock)
+{
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ guint bitfield = 0;
+ guint i;
+
+ g_return_val_if_fail(DNF_IS_LOCK(lock), FALSE);
+
+ for (i = 0; i < priv->item_array->len; i++) {
+ auto item = static_cast<DnfLockItem *>(g_ptr_array_index(priv->item_array, i));
+ bitfield += 1 << item->type;
+ }
+ return bitfield;
+}
+
+/**
+ * dnf_lock_emit_state:
+ **/
+static void
+dnf_lock_emit_state(DnfLock *lock)
+{
+ guint bitfield = 0;
+ bitfield = dnf_lock_get_state(lock);
+ g_signal_emit(lock, signals [SIGNAL_STATE_CHANGED], 0, bitfield);
+}
+
+/**
+ * dnf_lock_take:
+ * @lock: a #DnfLock instance.
+ * @type: A #ZifLockType, e.g. %DNF_LOCK_TYPE_RPMDB
+ * @mode: A #ZifLockMode, e.g. %DNF_LOCK_MODE_PROCESS
+ * @error: A #GError, or %NULL
+ *
+ * Tries to take a lock for the packaging system.
+ *
+ * Returns: A lock ID greater than 0, or 0 for an error.
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_lock_take(DnfLock *lock,
+ DnfLockType type,
+ DnfLockMode mode,
+ GError **error) try
+{
+ DnfLockItem *item;
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ gboolean ret;
+ guint id = 0;
+ guint pid;
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *cmdline = NULL;
+ g_autofree gchar *filename = NULL;
+ g_autofree gchar *pid_filename = NULL;
+ g_autofree gchar *pid_text = NULL;
+
+ g_return_val_if_fail(DNF_IS_LOCK(lock), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* lock other threads */
+ g_mutex_lock(&priv->mutex);
+
+ /* find the lock type, and ensure we find a process lock for
+ * a thread lock */
+ item = dnf_lock_get_item_by_type_mode(lock, type, mode);
+ if (item == NULL && mode == DNF_LOCK_MODE_THREAD) {
+ item = dnf_lock_get_item_by_type_mode(lock,
+ type,
+ DNF_LOCK_MODE_PROCESS);
+ }
+
+ /* create a lock file for process locks */
+ if (item == NULL && mode == DNF_LOCK_MODE_PROCESS) {
+
+ /* does lock file already exists? */
+ filename = dnf_lock_get_filename_for_type(lock, type);
+ if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
+
+ /* check the pid is still valid */
+ pid = dnf_lock_get_pid(lock, filename, error);
+ if (pid == 0)
+ goto out;
+
+ /* pid is not still running? */
+ pid_filename = g_strdup_printf("/proc/%i/cmdline", pid);
+ ret = g_file_test(pid_filename, G_FILE_TEST_EXISTS);
+ if (ret) {
+ cmdline = dnf_lock_get_cmdline_for_pid(pid);
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_GET_LOCK,
+ "%s[%s] already locked by %s",
+ dnf_lock_type_to_string(type),
+ dnf_lock_mode_to_string(mode),
+ cmdline);
+ goto out;
+ }
+ }
+
+ /* create file with our process ID */
+ pid_text = g_strdup_printf("%i", getpid());
+ if (!g_file_set_contents(filename, pid_text, -1, &error_local)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_GET_LOCK,
+ "failed to obtain lock '%s': %s",
+ dnf_lock_type_to_string(type),
+ error_local->message);
+ goto out;
+ }
+ }
+
+ /* create new lock */
+ if (item == NULL) {
+ item = dnf_lock_create_item(lock, type, mode);
+ id = item->id;
+ dnf_lock_emit_state(lock);
+ goto out;
+ }
+
+ /* we're trying to lock something that's already locked
+ * in another thread */
+ if (item->owner != g_thread_self()) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_GET_LOCK,
+ "failed to obtain lock '%s' already taken by thread %p",
+ dnf_lock_type_to_string(type),
+ item->owner);
+ goto out;
+ }
+
+ /* increment ref count */
+ item->refcount++;
+
+ /* emit the new locking bitfield */
+ dnf_lock_emit_state(lock);
+
+ /* success */
+ id = item->id;
+out:
+ /* unlock other threads */
+ g_mutex_unlock(&priv->mutex);
+ return id;
+} CATCH_TO_GERROR(0)
+
+/**
+ * dnf_lock_release:
+ * @lock: a #DnfLock instance.
+ * @id: A lock ID, as given by zif_lock_take()
+ * @error: A #GError, or %NULL
+ *
+ * Tries to release a lock for the packaging system.
+ *
+ * Returns: %TRUE if we locked, else %FALSE and the error is set
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_lock_release(DnfLock *lock, guint id, GError **error) try
+{
+ DnfLockItem *item;
+ DnfLockPrivate *priv = GET_PRIVATE(lock);
+ gboolean ret = FALSE;
+
+ g_assert(DNF_IS_LOCK(lock));
+ g_assert(id != 0);
+ g_assert(error == NULL || *error == NULL);
+
+ /* lock other threads */
+ g_mutex_lock(&priv->mutex);
+
+ /* never took */
+ item = dnf_lock_get_item_by_id(lock, id);
+ if (item == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Lock was never taken with id %i", id);
+ goto out;
+ }
+
+ /* not the same thread */
+ if (item->owner != g_thread_self()) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Lock %s was not taken by this thread",
+ dnf_lock_type_to_string(item->type));
+ goto out;
+ }
+
+ /* decrement ref count */
+ item->refcount--;
+
+ /* delete file for process locks */
+ if (item->refcount == 0 &&
+ item->mode == DNF_LOCK_MODE_PROCESS) {
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *filename = NULL;
+ g_autoptr(GFile) file = NULL;
+
+ /* unlink */
+ filename = dnf_lock_get_filename_for_type(lock, item->type);
+ file = g_file_new_for_path(filename);
+ ret = g_file_delete(file, NULL, &error_local);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to write: %s",
+ error_local->message);
+ goto out;
+ }
+ }
+
+ /* no thread now owns this lock */
+ if (item->refcount == 0)
+ g_ptr_array_remove(priv->item_array, item);
+
+ /* emit the new locking bitfield */
+ dnf_lock_emit_state(lock);
+
+ /* success */
+ ret = TRUE;
+out:
+ /* unlock other threads */
+ g_mutex_unlock(&priv->mutex);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_lock_release_noerror:
+ * @lock: a #DnfLock instance.
+ * @id: A lock ID, as given by zif_lock_take()
+ *
+ * Tries to release a lock for the packaging system. This method
+ * should not be used lightly as no error will be returned.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_lock_release_noerror(DnfLock *lock, guint id)
+{
+ g_autoptr(GError) error = NULL;
+ if (!dnf_lock_release(lock, id, &error))
+ g_warning("Handled locally: %s", error->message);
+}
+/**
+ * dnf_lock_new:
+ *
+ * Creates a new #DnfLock.
+ *
+ * Returns:(transfer full): a #DnfLock
+ *
+ * Since: 0.1.0
+ **/
+DnfLock *
+dnf_lock_new(void)
+{
+ if (dnf_lock_object != NULL) {
+ g_object_ref(dnf_lock_object);
+ } else {
+ dnf_lock_object = g_object_new(DNF_TYPE_LOCK, NULL);
+ g_object_add_weak_pointer(static_cast<GObject *>(dnf_lock_object), &dnf_lock_object);
+ }
+ return DNF_LOCK(dnf_lock_object);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_LOCK_H
+#define __DNF_LOCK_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_LOCK (dnf_lock_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfLock, dnf_lock, DNF, LOCK, GObject)
+
+struct _DnfLockClass
+{
+ GObjectClass parent_class;
+ void (* state_changed) (DnfLock *lock,
+ guint state_bitfield);
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+/**
+ * DnfLockType:
+ * @DNF_LOCK_TYPE_RPMDB: The rpmdb lock
+ * @DNF_LOCK_TYPE_REPO: The repodir lock
+ * @DNF_LOCK_TYPE_METADATA: The metadata lock
+ * @DNF_LOCK_TYPE_CONFIG: The config lock
+ *
+ * The lock type.
+ **/
+typedef enum {
+ DNF_LOCK_TYPE_RPMDB,
+ DNF_LOCK_TYPE_REPO,
+ DNF_LOCK_TYPE_METADATA,
+ DNF_LOCK_TYPE_CONFIG,
+ /*< private >*/
+ DNF_LOCK_TYPE_LAST
+} DnfLockType;
+
+/**
+ * DnfLockMode:
+ * @DNF_LOCK_MODE_THREAD: For all threads in this process
+ * @DNF_LOCK_MODE_PROCESS: For all processes
+ *
+ * The lock mode.
+ **/
+typedef enum {
+ DNF_LOCK_MODE_THREAD,
+ DNF_LOCK_MODE_PROCESS,
+ /*< private >*/
+ DNF_LOCK_MODE_LAST
+} DnfLockMode;
+
+DnfLock *dnf_lock_new (void);
+
+/* getters */
+guint dnf_lock_get_state (DnfLock *lock);
+void dnf_lock_set_lock_dir (DnfLock *lock,
+ const gchar *lock_dir);
+
+/* object methods */
+guint dnf_lock_take (DnfLock *lock,
+ DnfLockType type,
+ DnfLockMode mode,
+ GError **error);
+gboolean dnf_lock_release (DnfLock *lock,
+ guint id,
+ GError **error);
+void dnf_lock_release_noerror (DnfLock *lock,
+ guint id);
+const gchar *dnf_lock_type_to_string (DnfLockType lock_type);
+
+G_END_DECLS
+
+#endif /* __DNF_LOCK_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/**
+ * SECTION:dnf-goal
+ * @short_description: Helper methods for dealing with hawkey packages.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * These methods make it easier to get and set extra data on a package.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <assert.h>
+
+#include <librepo/librepo.h>
+#include <memory>
+
+#include "catch-error.hpp"
+#include "dnf-context.hpp"
+#include "dnf-package.h"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+#include "hy-util.h"
+#include "repo/solvable/Dependency.hpp"
+#include "repo/solvable/DependencyContainer.hpp"
+#include "utils/url-encode.hpp"
+
+typedef struct {
+ char *checksum_str;
+ gboolean user_action;
+ gchar *filename;
+ gchar *origin;
+ gchar *package_id;
+ DnfPackageInfo info;
+ DnfStateAction action;
+ DnfRepo *repo;
+} DnfPackagePrivate;
+
+/**
+ * dnf_package_destroy_func:
+ **/
+static void
+dnf_package_destroy_func(void *userdata)
+{
+ DnfPackagePrivate *priv =(DnfPackagePrivate *) userdata;
+ g_free(priv->filename);
+ g_free(priv->origin);
+ g_free(priv->package_id);
+ g_free(priv->checksum_str);
+ g_slice_free(DnfPackagePrivate, priv);
+}
+
+/**
+ * dnf_package_get_priv:
+ **/
+static DnfPackagePrivate *
+dnf_package_get_priv(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+
+ /* create private area */
+ priv = (DnfPackagePrivate*)g_object_get_data(G_OBJECT(pkg), "DnfPackagePrivate");
+ if (priv != NULL)
+ return priv;
+
+ priv = g_slice_new0(DnfPackagePrivate);
+ g_object_set_data_full(G_OBJECT(pkg), "DnfPackagePrivate", priv, dnf_package_destroy_func);
+ return priv;
+}
+
+/**
+ * dnf_package_is_local:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns: %TRUE if the pkg is a pkg on local or media filesystem
+ *
+ * Since: 0.38.2
+ **/
+gboolean
+dnf_package_is_local(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+
+ assert(priv->repo);
+
+ if (!dnf_repo_is_local(priv->repo))
+ return FALSE;
+
+ const gchar *url_location = dnf_package_get_baseurl(pkg);
+ return (!url_location || (url_location && g_str_has_prefix(url_location, "file:/")));
+}
+
+/**
+ * dnf_package_get_local_baseurl:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns package baseurl converted to a local filesystem path (i.e. "file://"
+ * is stripped and the URL is decoded). In case the URL is not local, returns
+ * %NULL.
+ *
+ * The returned string is newly allocated and ownership is transferred to the
+ * caller.
+ *
+ * Returns: local filesystem baseurl or %NULL
+ *
+ * Since: 0.54.0
+ **/
+gchar *
+dnf_package_get_local_baseurl(DnfPackage *pkg, GError **error)
+{
+ const gchar *baseurl = dnf_package_get_baseurl(pkg);
+
+ if (!baseurl || !g_str_has_prefix(baseurl, "file://")) {
+ return nullptr;
+ }
+
+ return g_strdup(libdnf::urlDecode(baseurl + 7).c_str());
+}
+
+/**
+ * dnf_package_get_filename:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the package filename.
+ *
+ * Returns: absolute filename, or %NULL
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_package_get_filename(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+
+ priv = dnf_package_get_priv(pkg);
+ if (!priv)
+ return NULL;
+ if (dnf_package_installed(pkg))
+ return NULL;
+ if (!priv->filename && !priv->repo)
+ return NULL;
+
+ /* default cache filename location */
+ if (!priv->filename) {
+ if (dnf_package_is_local(pkg)) {
+ const gchar *url_location = dnf_package_get_baseurl(pkg);
+ if (!url_location){
+ url_location = dnf_repo_get_location(priv->repo);
+ }
+ priv->filename = g_build_filename(url_location,
+ dnf_package_get_location(pkg),
+ NULL);
+ } else {
+ /* set the filename to cachedir for non-local repos */
+ g_autofree gchar *basename = NULL;
+ basename = g_path_get_basename(dnf_package_get_location(pkg));
+ priv->filename = g_build_filename(dnf_repo_get_packages(priv->repo),
+ basename,
+ NULL);
+ }
+ g_assert (priv->filename); /* Pacify static analysis */
+ }
+
+ /* remove file:// from filename */
+ if (g_str_has_prefix(priv->filename, "file:///")){
+ gchar *tmp = priv->filename;
+ priv->filename = g_strdup(tmp + 7);
+ g_free(tmp);
+ goto out;
+ }
+
+ /* remove file: from filename */
+ if (strlen(priv->filename) >= 7){
+ if (g_str_has_prefix(priv->filename, "file:/")){
+ if (priv->filename[6] != '/'){
+ gchar *tmp = priv->filename;
+ priv->filename = g_strdup(tmp + 5);
+ g_free(tmp);
+ }
+ }
+ }
+out:
+ return priv->filename;
+}
+
+/**
+ * dnf_package_get_origin:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the package origin.
+ *
+ * Returns: the package origin, or %NULL
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_package_get_origin(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return NULL;
+ if (!dnf_package_installed(pkg))
+ return NULL;
+ return priv->origin;
+}
+
+/**
+ * dnf_package_get_pkgid:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the pkgid, which is the SHA hash of the package header.
+ *
+ * Returns: pkgid string, or NULL
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_package_get_pkgid(DnfPackage *pkg)
+{
+ const unsigned char *checksum;
+ DnfPackagePrivate *priv;
+ int checksum_type;
+
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return NULL;
+ if (priv->checksum_str != NULL)
+ goto out;
+
+ /* calculate and cache */
+ checksum = dnf_package_get_hdr_chksum(pkg, &checksum_type);
+ if (checksum == NULL)
+ goto out;
+ priv->checksum_str = hy_chksum_str(checksum, checksum_type);
+out:
+ return priv->checksum_str;
+}
+
+/**
+ * dnf_package_set_pkgid:
+ * @pkg: a #DnfPackage *instance.
+ * @pkgid: pkgid, e.g. "e6e3b2b10c1ef1033769147dbd1bf851c7de7699"
+ *
+ * Sets the package pkgid, which is the SHA hash of the package header.
+ *
+ * Since: 0.1.8
+ **/
+void
+dnf_package_set_pkgid(DnfPackage *pkg, const gchar *pkgid)
+{
+ DnfPackagePrivate *priv;
+ g_return_if_fail(pkgid != NULL);
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ g_free(priv->checksum_str);
+ priv->checksum_str = strdup(pkgid);
+}
+
+/**
+ * dnf_package_id_build:
+ **/
+static gchar *
+dnf_package_id_build(const gchar *name,
+ const gchar *version,
+ const gchar *arch,
+ const gchar *data)
+{
+ return g_strjoin(";", name,
+ version != NULL ? version : "",
+ arch != NULL ? arch : "",
+ data != NULL ? data : "",
+ NULL);
+}
+
+/**
+ * dnf_package_get_package_id:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the package-id as used by PackageKit.
+ *
+ * Returns: the package_id string, or %NULL, e.g. "hal;2:0.3.4;i386;installed:fedora"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_package_get_package_id(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ const gchar *reponame;
+ g_autofree gchar *reponame_tmp = NULL;
+
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return NULL;
+ if (priv->package_id != NULL)
+ goto out;
+
+ /* calculate and cache */
+ reponame = dnf_package_get_reponame(pkg);
+ if (g_strcmp0(reponame, HY_SYSTEM_REPO_NAME) == 0) {
+ /* origin data to munge into the package_id data field */
+ if (priv->origin != NULL) {
+ reponame_tmp = g_strdup_printf("installed:%s", priv->origin);
+ reponame = reponame_tmp;
+ } else {
+ reponame = "installed";
+ }
+ } else if (g_strcmp0(reponame, HY_CMDLINE_REPO_NAME) == 0) {
+ reponame = "local";
+ }
+ priv->package_id = dnf_package_id_build(dnf_package_get_name(pkg),
+ dnf_package_get_evr(pkg),
+ dnf_package_get_arch(pkg),
+ reponame);
+out:
+ return priv->package_id;
+}
+
+/**
+ * dnf_package_get_cost:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns the cost of the repo that provided the package.
+ *
+ * Returns: the cost, where higher is more expensive, default 1000
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_package_get_cost(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv->repo == NULL) {
+ g_warning("no repo for %s", dnf_package_get_package_id(pkg));
+ return G_MAXUINT;
+ }
+ return dnf_repo_get_cost(priv->repo);
+}
+
+/**
+ * dnf_package_set_filename:
+ * @pkg: a #DnfPackage *instance.
+ * @filename: absolute filename.
+ *
+ * Sets the file on disk that matches the package repo.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_package_set_filename(DnfPackage *pkg, const gchar *filename)
+{
+ DnfPackagePrivate *priv;
+
+ /* replace contents */
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ g_free(priv->filename);
+ priv->filename = g_strdup(filename);
+}
+
+/**
+ * dnf_package_set_origin:
+ * @pkg: a #DnfPackage *instance.
+ * @origin: origin, e.g. "fedora"
+ *
+ * Sets the package origin repo.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_package_set_origin(DnfPackage *pkg, const gchar *origin)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ g_free(priv->origin);
+ priv->origin = g_strdup(origin);
+}
+
+/**
+ * dnf_package_set_repo:
+ * @pkg: a #DnfPackage *instance.
+ * @repo: a #DnfRepo.
+ *
+ * Sets the repo the package was created from.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_package_set_repo(DnfPackage *pkg, DnfRepo *repo)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ priv->repo = repo;
+}
+
+/**
+ * dnf_package_get_repo:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the repo the package was created from.
+ *
+ * Returns: a #DnfRepo or %NULL
+ *
+ * Since: 0.1.0
+ **/
+DnfRepo *
+dnf_package_get_repo(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return NULL;
+ return priv->repo;
+}
+
+/**
+ * dnf_package_get_info:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the info enum assigned to the package.
+ *
+ * Returns: #DnfPackageInfo value
+ *
+ * Since: 0.1.0
+ **/
+DnfPackageInfo
+dnf_package_get_info(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return DNF_PACKAGE_INFO_UNKNOWN;
+ return priv->info;
+}
+
+/**
+ * dnf_package_get_action:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets the action assigned to the package, i.e. what is going to be performed.
+ *
+ * Returns: a #DnfStateAction
+ *
+ * Since: 0.1.0
+ */
+DnfStateAction
+dnf_package_get_action(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return DNF_STATE_ACTION_UNKNOWN;
+ return priv->action;
+}
+
+/**
+ * dnf_package_set_info:
+ * @pkg: a #DnfPackage *instance.
+ * @info: the info flags.
+ *
+ * Sets the info flags for the package.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_package_set_info(DnfPackage *pkg, DnfPackageInfo info)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ priv->info = info;
+}
+
+/**
+ * dnf_package_set_action:
+ * @pkg: a #DnfPackage *instance.
+ * @action: the #DnfStateAction for the package.
+ *
+ * Sets the action for the package, i.e. what is going to be performed.
+ *
+ * Since: 0.1.0
+ */
+void
+dnf_package_set_action(DnfPackage *pkg, DnfStateAction action)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ priv->action = action;
+}
+
+/**
+ * dnf_package_get_user_action:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Gets if the package was installed or removed as the user action.
+ *
+ * Returns: %TRUE if the package was explicitly requested
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_package_get_user_action(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return FALSE;
+ return priv->user_action;
+}
+
+/**
+ * dnf_package_set_user_action:
+ * @pkg: a #DnfPackage *instance.
+ * @user_action: %TRUE if the package was explicitly requested.
+ *
+ * Sets if the package was installed or removed as the user action.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_package_set_user_action(DnfPackage *pkg, gboolean user_action)
+{
+ DnfPackagePrivate *priv;
+ priv = dnf_package_get_priv(pkg);
+ if (priv == NULL)
+ return;
+ priv->user_action = user_action;
+}
+
+/**
+ * dnf_package_is_gui:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns: %TRUE if the package is a GUI package
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_package_is_gui(DnfPackage *pkg)
+{
+ gboolean ret = FALSE;
+ const gchar *tmp;
+ gint idx;
+ gint size;
+
+ /* find if the package depends on GTK or KDE */
+ std::unique_ptr<DnfReldepList> reldep_list(dnf_package_get_requires(pkg));
+ size = reldep_list->count();
+ for (idx = 0; idx < size && !ret; idx++) {
+ auto reldep = reldep_list->get(idx);
+ tmp = reldep->toString();
+ if (g_strstr_len(tmp, -1, "libgtk") != NULL ||
+ g_strstr_len(tmp, -1, "libQt5Gui.so") != NULL ||
+ g_strstr_len(tmp, -1, "libQtGui.so") != NULL ||
+ g_strstr_len(tmp, -1, "libqt-mt.so") != NULL) {
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * dnf_package_is_devel:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns: %TRUE if the package is a development package
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_package_is_devel(DnfPackage *pkg)
+{
+ const gchar *name;
+ name = dnf_package_get_name(pkg);
+ if (g_str_has_suffix(name, "-debuginfo"))
+ return TRUE;
+ if (g_str_has_suffix(name, "-devel"))
+ return TRUE;
+ if (g_str_has_suffix(name, "-static"))
+ return TRUE;
+ if (g_str_has_suffix(name, "-libs"))
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * dnf_package_is_downloaded:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns: %TRUE if the package is already downloaded
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_package_is_downloaded(DnfPackage *pkg)
+{
+ const gchar *filename;
+
+ if (dnf_package_installed(pkg))
+ return FALSE;
+ filename = dnf_package_get_filename(pkg);
+ if (filename == NULL) {
+ g_warning("Failed to get cache filename for %s",
+ dnf_package_get_name(pkg));
+ return FALSE;
+ }
+ return g_file_test(filename, G_FILE_TEST_EXISTS);
+}
+
+/**
+ * dnf_package_is_installonly:
+ * @pkg: a #DnfPackage *instance.
+ *
+ * Returns: %TRUE if the package can be installed more than once
+ *
+ * Since: 0.1.0
+ */
+gboolean
+dnf_package_is_installonly(DnfPackage *pkg)
+{
+ if (auto * pkg_name = dnf_package_get_name(pkg)) {
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ for (auto & inst_only_pkg_name : mainConf.installonlypkgs().getValue()) {
+ if (inst_only_pkg_name == pkg_name) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * dnf_repo_checksum_hy_to_lr:
+ **/
+static LrChecksumType
+dnf_repo_checksum_hy_to_lr(GChecksumType checksum)
+{
+ if (checksum == G_CHECKSUM_MD5)
+ return LR_CHECKSUM_MD5;
+ if (checksum == G_CHECKSUM_SHA1)
+ return LR_CHECKSUM_SHA1;
+ if (checksum == G_CHECKSUM_SHA256)
+ return LR_CHECKSUM_SHA256;
+ if (checksum == G_CHECKSUM_SHA384)
+ return LR_CHECKSUM_SHA384;
+ return LR_CHECKSUM_SHA512;
+}
+
+/**
+ * dnf_package_check_filename:
+ * @pkg: a #DnfPackage *instance.
+ * @valid: Set to %TRUE if the package is valid.
+ * @error: a #GError or %NULL..
+ *
+ * Checks the package is already downloaded and valid.
+ *
+ * Returns: %TRUE if the package was checked successfully
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_package_check_filename(DnfPackage *pkg, gboolean *valid, GError **error) try
+{
+ LrChecksumType checksum_type_lr;
+ char *checksum_valid = NULL;
+ const gchar *path;
+ const unsigned char *checksum;
+ gboolean ret = TRUE;
+ int checksum_type_hy;
+ int fd;
+
+ /* check if the file does not exist */
+ path = dnf_package_get_filename(pkg);
+ g_debug("checking if %s already exists...", path);
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ *valid = FALSE;
+
+ /* a missing file in a local repo is an error, unless it is remote via base:url,
+ * since we can't download it */
+ if (dnf_package_is_local(pkg)) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "File missing in local repository %s", path);
+ }
+
+ goto out;
+ }
+
+ /* check the checksum */
+ checksum = dnf_package_get_chksum(pkg, &checksum_type_hy);
+ checksum_valid = hy_chksum_str(checksum, checksum_type_hy);
+ checksum_type_lr = dnf_repo_checksum_hy_to_lr((GChecksumType)checksum_type_hy);
+ fd = g_open(path, O_RDONLY, 0);
+ if (fd < 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Failed to open %s", path);
+ goto out;
+ }
+ ret = lr_checksum_fd_cmp(checksum_type_lr,
+ fd,
+ checksum_valid,
+ TRUE, /* use xattr value */
+ valid,
+ error);
+ if (!ret) {
+ g_close(fd, NULL);
+ goto out;
+ }
+ ret = g_close(fd, error);
+ if (!ret)
+ goto out;
+
+ /* A checksum mismatch for a package in a local repository is an
+ error. We can't repair it by downloading a corrected version,
+ so let's fail here. */
+ if (!*valid && dnf_repo_is_local (dnf_package_get_repo (pkg))) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Checksum mismatch in local repository %s", path);
+ goto out;
+ }
+
+out:
+ g_free(checksum_valid);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_package_download:
+ * @pkg: a #DnfPackage *instance.
+ * @directory: destination directory, or %NULL for the cachedir.
+ * @state: the #DnfState.
+ * @error: a #GError or %NULL..
+ *
+ * Downloads the package.
+ *
+ * Returns: the complete filename of the downloaded file
+ *
+ * Since: 0.1.0
+ **/
+gchar *
+dnf_package_download(DnfPackage *pkg,
+ const gchar *directory,
+ DnfState *state,
+ GError **error) try
+{
+ DnfRepo *repo;
+ repo = dnf_package_get_repo(pkg);
+ if (repo == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "package repo is unset");
+ return NULL;
+ }
+ return dnf_repo_download_package(repo, pkg, directory, state, error);
+} CATCH_TO_GERROR(NULL)
+
+/**
+ * dnf_package_array_download:
+ * @packages: an array of packages.
+ * @directory: destination directory, or %NULL for the cachedir.
+ * @state: the #DnfState.
+ * @error: a #GError or %NULL..
+ *
+ * Downloads an array of packages.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.1.0
+ */
+gboolean
+dnf_package_array_download(GPtrArray *packages,
+ const gchar *directory,
+ DnfState *state,
+ GError **error) try
+{
+ DnfState *state_local;
+ GHashTableIter hiter;
+ gpointer key, value;
+ guint i;
+ g_autoptr(GHashTable) repo_to_packages = NULL;
+
+ /* map packages to repos */
+ repo_to_packages = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_ptr_array_unref);
+ for (i = 0; i < packages->len; i++) {
+ DnfPackage *pkg = (DnfPackage*)g_ptr_array_index(packages, i);
+ DnfRepo *repo;
+ GPtrArray *repo_packages;
+
+ repo = dnf_package_get_repo(pkg);
+ if (repo == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "package repo is unset");
+ return FALSE;
+ }
+ repo_packages = (GPtrArray*)g_hash_table_lookup(repo_to_packages, repo);
+ if (repo_packages == NULL) {
+ repo_packages = g_ptr_array_new();
+ g_hash_table_insert(repo_to_packages, repo, repo_packages);
+ }
+ g_ptr_array_add(repo_packages, pkg);
+ }
+
+ /* set steps according to the number of repos we are going to download from */
+ dnf_state_set_number_steps(state, g_hash_table_size(repo_to_packages));
+
+ /* download all packages from each repo in one go */
+ g_hash_table_iter_init(&hiter, repo_to_packages);
+ while (g_hash_table_iter_next(&hiter, &key, &value)) {
+ DnfRepo *repo = (DnfRepo*)key;
+ GPtrArray *repo_packages = (GPtrArray*)value;
+
+ state_local = dnf_state_get_child(state);
+ if (!dnf_repo_download_packages(repo, repo_packages, directory, state_local, error))
+ return FALSE;
+
+ /* done */
+ if (!dnf_state_done(state, error))
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_package_array_get_download_size:
+ * @packages: an array of packages.
+ *
+ * Gets the download size for an array of packages.
+ *
+ * Returns: the download size
+ *
+ * Since: 0.2.3
+ */
+guint64
+dnf_package_array_get_download_size(GPtrArray *packages)
+{
+ guint i;
+ guint64 download_size = 0;
+
+ for (i = 0; i < packages->len; i++) {
+ DnfPackage *pkg = (DnfPackage*)g_ptr_array_index(packages, i);
+
+ download_size += dnf_package_get_downloadsize(pkg);
+ }
+
+ return download_size;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_PACKAGE_H
+#define __DNF_PACKAGE_H
+
+#include <glib.h>
+
+#include "hy-package.h"
+
+#include "dnf-repo.h"
+#include "dnf-state.h"
+
+G_BEGIN_DECLS
+
+/**
+ * DnfPackageInfo:
+ * @DNF_PACKAGE_INFO_UNKNOWN: Unknown state
+ * @DNF_PACKAGE_INFO_UPDATE: Package update
+ * @DNF_PACKAGE_INFO_INSTALL: Package install
+ * @DNF_PACKAGE_INFO_REMOVE: Package remove
+ * @DNF_PACKAGE_INFO_CLEANUP: Package cleanup
+ * @DNF_PACKAGE_INFO_OBSOLETE: Package obsolete
+ * @DNF_PACKAGE_INFO_REINSTALL: Package re-install
+ * @DNF_PACKAGE_INFO_DOWNGRADE: Package downgrade
+ *
+ * The info enum code.
+ **/
+typedef enum {
+ DNF_PACKAGE_INFO_UNKNOWN = 0,
+ DNF_PACKAGE_INFO_UPDATE = 11,
+ DNF_PACKAGE_INFO_INSTALL = 12,
+ DNF_PACKAGE_INFO_REMOVE = 13,
+ DNF_PACKAGE_INFO_CLEANUP = 14,
+ DNF_PACKAGE_INFO_OBSOLETE = 15,
+ DNF_PACKAGE_INFO_REINSTALL = 19,
+ DNF_PACKAGE_INFO_DOWNGRADE = 20,
+ /*< private >*/
+ DNF_PACKAGE_INFO_LAST
+} DnfPackageInfo;
+
+DnfRepo *dnf_package_get_repo (DnfPackage *pkg);
+void dnf_package_set_repo (DnfPackage *pkg,
+ DnfRepo *repo);
+const gchar *dnf_package_get_filename (DnfPackage *pkg);
+void dnf_package_set_filename (DnfPackage *pkg,
+ const gchar *filename);
+const gchar *dnf_package_get_origin (DnfPackage *pkg);
+void dnf_package_set_origin (DnfPackage *pkg,
+ const gchar *origin);
+const gchar *dnf_package_get_package_id (DnfPackage *pkg);
+DnfPackageInfo dnf_package_get_info (DnfPackage *pkg);
+void dnf_package_set_info (DnfPackage *pkg,
+ DnfPackageInfo info);
+DnfStateAction dnf_package_get_action (DnfPackage *pkg);
+void dnf_package_set_action (DnfPackage *pkg,
+ DnfStateAction action);
+gboolean dnf_package_get_user_action (DnfPackage *pkg);
+void dnf_package_set_user_action (DnfPackage *pkg,
+ gboolean user_action);
+gboolean dnf_package_is_gui (DnfPackage *pkg);
+gboolean dnf_package_is_devel (DnfPackage *pkg);
+gboolean dnf_package_is_local (DnfPackage *pkg);
+gchar *dnf_package_get_local_baseurl (DnfPackage *pkg,
+ GError **error);
+gboolean dnf_package_is_downloaded (DnfPackage *pkg);
+gboolean dnf_package_is_installonly (DnfPackage *pkg);
+const gchar *dnf_package_get_pkgid (DnfPackage *pkg);
+void dnf_package_set_pkgid (DnfPackage *pkg,
+ const gchar *pkgid);
+guint dnf_package_get_cost (DnfPackage *pkg);
+gchar *dnf_package_download (DnfPackage *pkg,
+ const gchar *directory,
+ DnfState *state,
+ GError **error);
+gboolean dnf_package_check_filename (DnfPackage *pkg,
+ gboolean *valid,
+ GError **error);
+
+gboolean dnf_package_array_download (GPtrArray *packages,
+ const gchar *directory,
+ DnfState *state,
+ GError **error);
+guint64 dnf_package_array_get_download_size (GPtrArray *packages);
+
+G_END_DECLS
+
+#endif /* __DNF_PACKAGE_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_PACKAGEDELTA_PRIVATE_H
+#define __DNF_PACKAGEDELTA_PRIVATE_H
+
+#include "dnf-packagedelta.h"
+
+DnfPackageDelta *dnf_packagedelta_new (Pool *pool);
+
+#endif /* __DNF_PACKAGEDELTA_PRIVATE_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-packagedelta
+ * @short_description: Package delta
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * An object representing a package delta.
+ *
+ * See also: #DnfContext
+ */
+
+
+#include <solv/repodata.h>
+#include <solv/util.h>
+
+#include "dnf-packagedelta-private.hpp"
+#include "hy-iutil-private.hpp"
+
+typedef struct
+{
+ char *location;
+ char *baseurl;
+ guint64 downloadsize;
+ int checksum_type;
+ unsigned char *checksum;
+} DnfPackageDeltaPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfPackageDelta, dnf_packagedelta, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfPackageDeltaPrivate *>(dnf_packagedelta_get_instance_private (o)))
+
+/**
+ * dnf_packagedelta_finalize:
+ **/
+static void
+dnf_packagedelta_finalize(GObject *object)
+{
+ DnfPackageDelta *packagedelta = DNF_PACKAGEDELTA(object);
+ DnfPackageDeltaPrivate *priv = GET_PRIVATE(packagedelta);
+
+ g_free(priv->location);
+ g_free(priv->baseurl);
+ g_free(priv->checksum);
+
+ G_OBJECT_CLASS(dnf_packagedelta_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_packagedelta_init:
+ **/
+static void
+dnf_packagedelta_init(DnfPackageDelta *packagedelta)
+{
+}
+
+/**
+ * dnf_packagedelta_class_init:
+ **/
+static void
+dnf_packagedelta_class_init(DnfPackageDeltaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_packagedelta_finalize;
+}
+
+/**
+ * dnf_packagedelta_new:
+ *
+ * Creates a new #DnfPackageDelta.
+ *
+ * Returns:(transfer full): a #DnfPackageDelta
+ *
+ * Since: 0.7.0
+ **/
+DnfPackageDelta *
+dnf_packagedelta_new(Pool *pool)
+{
+ Id checksum_type;
+
+ auto delta = DNF_PACKAGEDELTA(g_object_new(DNF_TYPE_PACKAGEDELTA, NULL));
+ auto priv = GET_PRIVATE(delta);
+
+ /* obtain info */
+ priv->location = g_strdup(pool_lookup_deltalocation(pool, SOLVID_POS, 0));
+ priv->baseurl = g_strdup(pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_BASE));
+ priv->downloadsize = pool_lookup_num(pool, SOLVID_POS, DELTA_DOWNLOADSIZE, 0);
+ auto checksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &checksum_type);
+ if (checksum) {
+ priv->checksum_type = checksumt_l2h(checksum_type);
+ priv->checksum = static_cast<unsigned char *>(
+ solv_memdup((void*)checksum, checksum_type2length(priv->checksum_type)));
+ }
+
+ return delta;
+}
+
+/**
+ * dnf_packagedelta_get_location:
+ * @delta: a #DnfPackageDelta instance.
+ *
+ * Gets the delta location.
+ *
+ * Returns: location URL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_packagedelta_get_location(DnfPackageDelta *delta)
+{
+ DnfPackageDeltaPrivate *priv = GET_PRIVATE(delta);
+ return priv->location;
+}
+
+/**
+ * dnf_packagedelta_get_baseurl:
+ * @delta: a #DnfPackageDelta instance.
+ *
+ * Gets the delta baseurl.
+ *
+ * Returns: string URL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_packagedelta_get_baseurl(DnfPackageDelta *delta)
+{
+ DnfPackageDeltaPrivate *priv = GET_PRIVATE(delta);
+ return priv->baseurl;
+}
+
+/**
+ * dnf_packagedelta_get_downloadsize:
+ * @delta: a #DnfPackageDelta instance.
+ *
+ * Gets the delta download size.
+ *
+ * Returns: size in bytes
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_packagedelta_get_downloadsize(DnfPackageDelta *delta)
+{
+ DnfPackageDeltaPrivate *priv = GET_PRIVATE(delta);
+ return priv->downloadsize;
+}
+
+/**
+ * dnf_packagedelta_get_chksum:
+ * @delta: a #DnfPackageDelta instance.
+ * @type: the checksum type
+ *
+ * Returns the checksum of the delta.
+ *
+ * Returns: checksum data
+ *
+ * Since: 0.7.0
+ */
+const unsigned char *
+dnf_packagedelta_get_chksum(DnfPackageDelta *delta, int *type)
+{
+ DnfPackageDeltaPrivate *priv = GET_PRIVATE(delta);
+ if (type)
+ *type = priv->checksum_type;
+ return priv->checksum;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_PACKAGEDELTA_H
+#define __DNF_PACKAGEDELTA_H
+
+#include <glib-object.h>
+
+#include <solv/pool.h>
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_PACKAGEDELTA (dnf_packagedelta_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfPackageDelta, dnf_packagedelta, DNF, PACKAGEDELTA, GObject)
+
+struct _DnfPackageDeltaClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+const char *dnf_packagedelta_get_location (DnfPackageDelta *delta);
+const char *dnf_packagedelta_get_baseurl (DnfPackageDelta *delta);
+guint64 dnf_packagedelta_get_downloadsize (DnfPackageDelta *delta);
+const unsigned char *dnf_packagedelta_get_chksum (DnfPackageDelta *delta, int *type);
+
+G_END_DECLS
+
+#endif /* __DNF_PACKAGEDELTA_H */
--- /dev/null
+/*
+ * Copyright © 2016 Igor Gnatenko <ignatenko@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dnf-reldep-list.h"
+#include "dnf-sack-private.hpp"
+#include "repo/solvable/Dependency.hpp"
+#include "repo/solvable/DependencyContainer.hpp"
+
+/**
+ * dnf_reldep_list_new:
+ * @sack: a #DnfSack
+ *
+ * Returns: an #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_reldep_list_new (DnfSack *sack)
+{
+ return new libdnf::DependencyContainer(sack);
+}
+
+/**
+ * dnf_reldep_list_free:
+ * @reldep_list: a #DnfReldepList
+ *
+ * Returns: Nothing
+ */
+void
+dnf_reldep_list_free (DnfReldepList *reldep_list)
+{
+ delete reldep_list;
+}
+
+/**
+ * dnf_reldep_list_add:
+ * @reldep_list: a #DnfReldepList
+ * @reldep: a #DnfReldep
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_reldep_list_add (DnfReldepList *reldep_list,
+ DnfReldep *reldep)
+{
+ reldep_list->add(reldep);
+}
+
+/**
+ * dnf_reldep_list_count:
+ * @reldep_list: a #DnfReldepList
+ *
+ * Returns: Number of RelDeps in queue.
+ *
+ * Since: 0.7.0
+ */
+gint
+dnf_reldep_list_count (DnfReldepList *reldep_list)
+{
+ return reldep_list->count();
+}
+
+/**
+ * dnf_reldep_list_index:
+ * @reldep_list: a #DnfReldepList
+ * @index: Index
+ *
+ * Returns: (transfer full): an #DnfReldep
+ *
+ * Since: 0.7.0
+ */
+DnfReldep *
+dnf_reldep_list_index (DnfReldepList *reldep_list,
+ gint index)
+{
+ return reldep_list->getPtr(index);
+}
+
+/**
+ * dnf_reldep_list_extend:
+ * @rl1: original #DnfReldepList
+ * @rl2: additional #DnfReldepList
+ *
+ * Extends @rl1 with elements from @rl2.
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_reldep_list_extend (DnfReldepList *rl1,
+ DnfReldepList *rl2)
+{
+ rl1->extend(rl2);
+}
--- /dev/null
+/*
+ * Copyright © 2016 Igor Gnatenko <ignatenko@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_RELDEPLIST_H
+#define LIBDNF_RELDEPLIST_H
+
+#include "dnf-reldep.h"
+#include "dnf-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DnfReldepList *dnf_reldep_list_new(DnfSack *sack);
+void dnf_reldep_list_free(DnfReldepList *reldep_list);
+DnfReldep *dnf_reldep_list_index(DnfReldepList *reldep_list, gint index);
+gint dnf_reldep_list_count(DnfReldepList *reldep_list);
+void dnf_reldep_list_add(DnfReldepList *reldep_list, DnfReldep *reldep);
+void dnf_reldep_list_extend(DnfReldepList *rl1, DnfReldepList *rl2);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(DnfReldepList, dnf_reldep_list_free)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDNF_RELDEPLIST_H
--- /dev/null
+/*
+ * Copyright © 2016 Igor Gnatenko <ignatenko@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <solv/pool.h>
+
+#include "dnf-types.h"
+#include "dnf-sack-private.hpp"
+#include "repo/solvable/Dependency.hpp"
+
+
+/**
+ * dnf_reldep_new:
+ * @sack: a #DnfSack
+ * @name: Name
+ * @cmp_type: Comparison type
+ * @evr: (nullable): EVR
+ *
+ * Returns: an #DnfReldep
+ *
+ * Since: 0.7.0
+ */
+DnfReldep *
+dnf_reldep_new (DnfSack *sack, const char *name, int cmp_type, const char *evr)
+{
+ return new libdnf::Dependency(sack, name, evr, cmp_type);
+}
+
+/**
+ * dnf_reldep_to_string:
+ * @reldep: a #DnfReldep
+ *
+ * Returns: a string
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_reldep_to_string (DnfReldep *reldep)
+{
+ return reldep->toString();
+}
+
+Id
+dnf_reldep_get_id (DnfReldep *reldep)
+{
+ return reldep->getId();
+}
+
+const char *
+dnf_reldep_get_name(DnfReldep * reldep)
+{
+ return reldep->getName();
+}
+
+const char *
+dnf_reldep_get_relation(DnfReldep * reldep)
+{
+ return reldep->getRelation();
+}
+
+const char *
+dnf_reldep_get_version(DnfReldep * reldep)
+{
+ return reldep->getVersion();
+}
+
+void dnf_reldep_free(DnfReldep *reldep)
+{
+ delete reldep;
+}
--- /dev/null
+/*
+ * Copyright © 2016 Igor Gnatenko <ignatenko@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_RELDEP_H
+#define LIBDNF_RELDEP_H
+
+#include <solv/pooltypes.h>
+
+#include "dnf-enums.h"
+#include "dnf-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DnfReldep *dnf_reldep_new(DnfSack *sack, const char *name, int cmp_type, const char *evr);
+const char *dnf_reldep_to_string(DnfReldep *reldep);
+Id dnf_reldep_get_id(DnfReldep *reldep);
+const char * dnf_reldep_get_name(DnfReldep * reldep);
+const char * dnf_reldep_get_relation(DnfReldep * reldep);
+const char * dnf_reldep_get_version(DnfReldep * reldep);
+void dnf_reldep_free(DnfReldep *reldep);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDNF_RELDEP_H
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-repo-loader
+ * @short_description: An object for loading several #DnfRepo objects.
+ * @include: libdnf.h
+ * @stability: Stable
+ *
+ * This object can create #DnfRepo objects from either DVD media or from .repo
+ * files in the repodir.
+ *
+ * See also: #DnfRepo
+ */
+
+#include <strings.h>
+
+#include <gio/gunixmounts.h>
+#include <librepo/util.h>
+#include <string.h>
+
+#include "catch-error.hpp"
+#include "dnf-package.h"
+#include "dnf-repo-loader.h"
+#include "dnf-utils.h"
+
+typedef struct
+{
+ GPtrArray *monitor_repos;
+ DnfContext *context; /* weak reference */
+ GPtrArray *repos;
+ GVolumeMonitor *volume_monitor;
+ gboolean loaded;
+} DnfRepoLoaderPrivate;
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfRepoLoader, dnf_repo_loader, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfRepoLoaderPrivate *>(dnf_repo_loader_get_instance_private (o)))
+
+/**
+ * dnf_repo_loader_invalidate:
+ */
+static void
+dnf_repo_loader_invalidate(DnfRepoLoader *self)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ priv->loaded = FALSE;
+ dnf_context_invalidate_full(priv->context, "repos.d invalidated",
+ DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT);
+}
+
+/**
+ * dnf_repo_loader_mount_changed_cb:
+ */
+static void
+dnf_repo_loader_mount_changed_cb(GVolumeMonitor *vm, GMount *mount, DnfRepoLoader *self)
+{
+ /* invalidate all repos if a CD is inserted / removed */
+ g_debug("emit changed(mounts changed)");
+ g_signal_emit(self, signals[SIGNAL_CHANGED], 0);
+ dnf_repo_loader_invalidate(self);
+}
+
+/**
+ * dnf_repo_loader_directory_changed_cb:
+ **/
+static void
+dnf_repo_loader_directory_changed_cb(GFileMonitor *monitor_,
+ GFile *file, GFile *other_file,
+ GFileMonitorEvent event_type,
+ DnfRepoLoader *self)
+{
+ g_debug("emit changed(ReposDir changed)");
+ g_signal_emit(self, signals[SIGNAL_CHANGED], 0);
+ dnf_repo_loader_invalidate(self);
+}
+
+/**
+ * dnf_repo_loader_finalize:
+ **/
+static void
+dnf_repo_loader_finalize(GObject *object)
+{
+ DnfRepoLoader *self = DNF_REPO_LOADER(object);
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+
+ if (priv->context != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->context),
+ (void **) &priv->context);
+ guint i;
+ for (i = 0; i < priv->monitor_repos->len; i++) {
+ auto repo_file_monitor = static_cast<GFileMonitor *>(g_ptr_array_index(priv->monitor_repos, i));
+ g_signal_handlers_disconnect_by_func(repo_file_monitor, (gpointer) dnf_repo_loader_directory_changed_cb, self);
+ }
+ g_ptr_array_unref(priv->monitor_repos);
+
+ g_signal_handlers_disconnect_by_func(priv->volume_monitor, (gpointer) dnf_repo_loader_mount_changed_cb, self);
+ g_object_unref(priv->volume_monitor);
+ g_ptr_array_unref(priv->repos);
+
+ G_OBJECT_CLASS(dnf_repo_loader_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_repo_loader_init:
+ **/
+static void
+dnf_repo_loader_init(DnfRepoLoader *self)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ priv->monitor_repos = g_ptr_array_new_with_free_func((GDestroyNotify) g_object_unref);
+ priv->repos = g_ptr_array_new_with_free_func((GDestroyNotify) g_object_unref);
+ priv->volume_monitor = g_volume_monitor_get();
+ g_signal_connect(priv->volume_monitor, "mount-added",
+ G_CALLBACK(dnf_repo_loader_mount_changed_cb), self);
+ g_signal_connect(priv->volume_monitor, "mount-removed",
+ G_CALLBACK(dnf_repo_loader_mount_changed_cb), self);
+}
+
+/**
+ * dnf_repo_loader_class_init:
+ **/
+static void
+dnf_repo_loader_class_init(DnfRepoLoaderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ /**
+ * DnfRepoLoader::changed:
+ **/
+ signals[SIGNAL_CHANGED] =
+ g_signal_new("changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfRepoLoaderClass, changed),
+ NULL, NULL, g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ object_class->finalize = dnf_repo_loader_finalize;
+}
+
+/**
+ * dnf_repo_loader_add_media:
+ **/
+static gboolean
+dnf_repo_loader_add_media(DnfRepoLoader *self,
+ const gchar *mount_point,
+ guint idx,
+ GError **error)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ DnfRepo *repo;
+ g_autofree gchar *treeinfo_fn = NULL;
+ g_autoptr(GKeyFile) treeinfo = NULL;
+
+ /* get common things */
+ treeinfo_fn = g_build_filename(mount_point, ".treeinfo", NULL);
+ treeinfo = g_key_file_new();
+ if (!g_key_file_load_from_file(treeinfo, treeinfo_fn, G_KEY_FILE_NONE, error))
+ return FALSE;
+
+ /* create read-only location */
+ repo = dnf_repo_new(priv->context);
+ dnf_repo_set_enabled(repo, DNF_REPO_ENABLED_PACKAGES);
+ dnf_repo_set_gpgcheck(repo, TRUE);
+ dnf_repo_set_kind(repo, DNF_REPO_KIND_MEDIA);
+ dnf_repo_set_skip_if_unavailable(repo, TRUE);
+ dnf_repo_set_cost(repo, 100);
+ dnf_repo_set_keyfile(repo, treeinfo);
+ if (idx == 0) {
+ dnf_repo_set_id(repo, "media");
+ } else {
+ g_autofree gchar *tmp = NULL;
+ tmp = g_strdup_printf("media-%i", idx);
+ dnf_repo_set_id(repo, tmp);
+ }
+ dnf_repo_set_location(repo, mount_point);
+ if (!dnf_repo_setup(repo, error))
+ return FALSE;
+
+ g_debug("added repo %s", dnf_repo_get_id(repo));
+ g_ptr_array_add(priv->repos, repo);
+ return TRUE;
+}
+
+/**
+ * dnf_repo_loader_add_sack_from_mount_point:
+ */
+static gboolean
+dnf_repo_loader_add_sack_from_mount_point(DnfRepoLoader *self,
+ const gchar *root,
+ guint *idx,
+ GError **error)
+{
+ const gchar *id = ".treeinfo";
+ gboolean exists;
+ g_autofree gchar *treeinfo_fn = NULL;
+
+ /* check if any installed media is an install disk */
+ treeinfo_fn = g_build_filename(root, id, NULL);
+ exists = g_file_test(treeinfo_fn, G_FILE_TEST_EXISTS);
+ g_debug("checking %s for %s: %s", root, id, exists ? "yes" : "no");
+ if (!exists)
+ return TRUE;
+
+ /* add the repodata/repomd.xml as a repo */
+ if (!dnf_repo_loader_add_media(self, root, *idx, error))
+ return FALSE;
+ (*idx)++;
+ return TRUE;
+}
+
+/**
+ * dnf_repo_loader_get_repos_removable:
+ */
+static gboolean
+dnf_repo_loader_get_repos_removable(DnfRepoLoader *self, GError **error)
+{
+ GList *mounts;
+ GList *l;
+ gboolean ret = TRUE;
+ guint idx = 0;
+
+ /* coldplug the mounts */
+ mounts = g_unix_mounts_get(NULL);
+ for (l = mounts; l != NULL; l = l->next) {
+ GUnixMountEntry *e =(GUnixMountEntry *) l->data;
+ if (!g_unix_mount_is_readonly(e))
+ continue;
+ if (g_strcmp0(g_unix_mount_get_fs_type(e), "iso9660") != 0)
+ continue;
+ ret = dnf_repo_loader_add_sack_from_mount_point(self,
+ g_unix_mount_get_mount_path(e),
+ &idx,
+ error);
+ if (!ret)
+ goto out;
+ }
+out:
+ g_list_foreach(mounts,(GFunc) g_unix_mount_free, NULL);
+ g_list_free(mounts);
+ return ret;
+}
+
+/**
+ * dnf_repo_loader_repo_cost_fn:
+ */
+static gint
+dnf_repo_loader_repo_cost_fn(gconstpointer a, gconstpointer b)
+{
+ DnfRepo *repo_a = *((DnfRepo **) a);
+ DnfRepo *repo_b = *((DnfRepo **) b);
+ if (dnf_repo_get_cost(repo_a) < dnf_repo_get_cost(repo_b))
+ return -1;
+ if (dnf_repo_get_cost(repo_a) > dnf_repo_get_cost(repo_b))
+ return 1;
+ return 0;
+}
+
+/**
+ * dnf_repo_loader_load_multiline_key_file:
+ **/
+static GKeyFile *
+dnf_repo_loader_load_multiline_key_file(const gchar *filename, GError **error)
+{
+ GKeyFile *file = NULL;
+ gboolean ret;
+ gsize len;
+ guint i;
+ g_autofree gchar *data = NULL;
+ g_autoptr(GString) string = NULL;
+ g_auto(GStrv) lines = NULL;
+
+ /* load file */
+ if (!g_file_get_contents(filename, &data, &len, error))
+ return NULL;
+
+ /* split into lines */
+ string = g_string_new("");
+ lines = g_strsplit(data, "\n", -1);
+ for (i = 0; lines[i] != NULL; i++) {
+
+ /* convert tabs to spaces */
+ g_strdelimit(lines[i], "\t", ' ');
+
+ /* if a line starts with whitespace, then append it on
+ * the previous line */
+ if (lines[i][0] == ' ' && string->len > 0) {
+
+ /* whitespace strip this new line */
+ g_strstrip(lines[i]);
+
+ /* skip over the line if it was only whitespace */
+ if (strlen(lines[i]) == 0)
+ continue;
+
+ /* remove old newline from previous line */
+ g_string_set_size(string, string->len - 1);
+
+ /* only add a ';' if we have anything after the '=' */
+ if (string->str[string->len - 1] == '=') {
+ g_string_append_printf(string, "%s\n", lines[i]);
+ } else {
+ g_string_append_printf(string, ";%s\n", lines[i]);
+ }
+ } else {
+ g_string_append_printf(string, "%s\n", lines[i]);
+ }
+ }
+
+ /* remove final newline */
+ if (string->len > 0)
+ g_string_set_size(string, string->len - 1);
+
+ /* load modified lines */
+ file = g_key_file_new();
+ ret = g_key_file_load_from_data(file,
+ string->str,
+ -1,
+ G_KEY_FILE_KEEP_COMMENTS,
+ error);
+ if (!ret) {
+ g_key_file_free(file);
+ return NULL;
+ }
+ return file;
+}
+
+/**
+ * dnf_repo_loader_repo_parse_id:
+ **/
+static gboolean
+dnf_repo_loader_repo_parse_id(DnfRepoLoader *self,
+ const gchar *id,
+ const gchar *filename,
+ GKeyFile *keyfile,
+ GError **error)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(DnfRepo) repo = NULL;
+
+ repo = dnf_repo_new(priv->context);
+ dnf_repo_set_kind(repo, DNF_REPO_KIND_REMOTE);
+ dnf_repo_set_keyfile(repo, keyfile);
+ dnf_repo_set_filename(repo, filename);
+ dnf_repo_set_id(repo, id);
+
+ /* set up the repo ready for use */
+ if (!dnf_repo_setup(repo, error))
+ return FALSE;
+
+ g_debug("added repo %s\t%s", filename, id);
+ g_ptr_array_add(priv->repos, g_object_ref(repo));
+ return TRUE;
+}
+
+/**
+ * dnf_repo_loader_repo_parse:
+ **/
+static gboolean
+dnf_repo_loader_repo_parse(DnfRepoLoader *self,
+ const gchar *filename,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ guint i;
+ g_auto(GStrv) groups = NULL;
+ g_autoptr(GKeyFile) keyfile = NULL;
+
+ /* load non-standard keyfile */
+ keyfile = dnf_repo_loader_load_multiline_key_file(filename, error);
+ if (keyfile == NULL) {
+ g_prefix_error(error, "Failed to load %s: ", filename);
+ return FALSE;
+ }
+
+ /* save all the repos listed in the file, "main" section is skipped - repoid can't be "main" */
+ groups = g_key_file_get_groups(keyfile, NULL);
+ for (i = 0; groups[i] != NULL; i++) {
+ if (strcmp(groups[i], "main") == 0) {
+ continue;
+ }
+ ret = dnf_repo_loader_repo_parse_id(self, groups[i], filename, keyfile, error);
+ if (!ret)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * dnf_repo_loader_refresh:
+ */
+static gboolean
+dnf_repo_loader_refresh(DnfRepoLoader *self, GError **error)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+
+ if (!dnf_context_plugin_hook(priv->context, PLUGIN_HOOK_ID_CONTEXT_PRE_REPOS_RELOAD, nullptr, nullptr))
+ return FALSE;
+
+ /* no longer loaded */
+ dnf_repo_loader_invalidate(self);
+ g_ptr_array_set_size(priv->repos, 0);
+
+ /* re-populate redhat.repo */
+ if (!dnf_context_setup_enrollments(priv->context, error))
+ return FALSE;
+
+ /* load repos defined in main configuration */
+ auto cfg_file_path = dnf_context_get_config_file_path();
+ if (cfg_file_path[0] != '\0' &&
+ (dnf_context_is_set_config_file_path() || g_file_test(cfg_file_path, G_FILE_TEST_IS_REGULAR))) {
+ if (!dnf_repo_loader_repo_parse(self, cfg_file_path, error)) {
+ return FALSE;
+ }
+ }
+
+ /* open dir */
+ auto repos_dir = dnf_context_get_repos_dir(priv->context);
+ for (auto item = repos_dir; *item; ++item) {
+ auto repo_path = *item;
+ g_autoptr(GDir) dir = g_dir_open(repo_path, 0, NULL);
+ // existence of repos directories is not mandatory
+ if (dir == NULL)
+ continue;
+
+ /* find all the .repo files */
+ while (auto file = g_dir_read_name(dir)) {
+ g_autofree gchar *path_tmp = NULL;
+ if (!g_str_has_suffix(file, ".repo"))
+ continue;
+ path_tmp = g_build_filename(repo_path, file, NULL);
+ if (!dnf_repo_loader_repo_parse(self, path_tmp, error))
+ return FALSE;
+ }
+ }
+
+ /* add any DVD repos */
+ if (!dnf_repo_loader_get_repos_removable(self, error))
+ return FALSE;
+
+ /* all okay */
+ priv->loaded = TRUE;
+
+ /* sort these in order of cost */
+ g_ptr_array_sort(priv->repos, dnf_repo_loader_repo_cost_fn);
+ return TRUE;
+}
+
+/**
+ * dnf_repo_loader_has_removable_repos:
+ */
+gboolean
+dnf_repo_loader_has_removable_repos(DnfRepoLoader *self)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ guint i;
+
+ g_return_val_if_fail(DNF_IS_REPO_LOADER(self), FALSE);
+
+ /* are there any media repos */
+ for (i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (dnf_repo_get_kind(repo) == DNF_REPO_KIND_MEDIA)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * dnf_repo_loader_get_repos:
+ *
+ * Returns:(transfer container)(element-type DnfRepo): Array of repos
+ */
+GPtrArray *
+dnf_repo_loader_get_repos(DnfRepoLoader *self, GError **error) try
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+
+ g_return_val_if_fail(DNF_IS_REPO_LOADER(self), NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* nothing set yet */
+ if (!priv->loaded) {
+ if (!dnf_repo_loader_refresh(self, error))
+ return NULL;
+ }
+
+ /* all okay */
+ return g_ptr_array_ref(priv->repos);
+} CATCH_TO_GERROR(NULL)
+
+/**
+ * dnf_repo_loader_get_repo_by_id:
+ */
+DnfRepo *
+dnf_repo_loader_get_repo_by_id(DnfRepoLoader *self, const gchar *id, GError **error) try
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ guint i;
+
+ g_return_val_if_fail(DNF_IS_REPO_LOADER(self), NULL);
+ g_return_val_if_fail(id != NULL, NULL);
+ g_return_val_if_fail(error == NULL || *error == NULL, NULL);
+
+ /* nothing set yet */
+ if (!priv->loaded) {
+ if (!dnf_repo_loader_refresh(self, error))
+ return NULL;
+ }
+
+ for (i = 0; i < priv->repos->len; i++) {
+ auto tmp = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
+ if (g_strcmp0(dnf_repo_get_id(tmp), id) == 0)
+ return tmp;
+ }
+
+ /* we didn't find anything */
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_FOUND,
+ "failed to find %s", id);
+ return NULL;
+} CATCH_TO_GERROR(NULL)
+
+/**
+ * dnf_repo_loader_setup_monitor:
+ */
+static void
+dnf_repo_loader_setup_monitor(DnfRepoLoader *self, const char * path, bool is_dir)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+ g_autoptr(GFile) file_path = g_file_new_for_path(path);
+ g_autoptr(GError) error = NULL;
+ GFileMonitor * monitor = NULL;
+ if (is_dir) {
+ monitor = g_file_monitor_directory(file_path, G_FILE_MONITOR_NONE, NULL, &error);
+ } else {
+ monitor = g_file_monitor_file(file_path, G_FILE_MONITOR_NONE, NULL, &error);
+ }
+ if (monitor) {
+ g_ptr_array_add(priv->monitor_repos, monitor);
+ g_signal_connect(monitor, "changed",
+ G_CALLBACK(dnf_repo_loader_directory_changed_cb), self);
+ } else {
+ g_warning("failed to setup monitor: %s",
+ error->message);
+ }
+}
+
+/**
+ * dnf_repo_loader_setup_watch:
+ */
+static void
+dnf_repo_loader_setup_watch(DnfRepoLoader *self)
+{
+ DnfRepoLoaderPrivate *priv = GET_PRIVATE(self);
+
+ /* setup a file monitor on the main configuration file */
+ auto cfg_file_path = dnf_context_get_config_file_path();
+ if (cfg_file_path[0] != '\0' && g_file_test(cfg_file_path, G_FILE_TEST_IS_REGULAR)) {
+ dnf_repo_loader_setup_monitor(self, cfg_file_path, false);
+ }
+
+ /* setup a file monitor on the repos directory */
+ auto repos_dir = dnf_context_get_repos_dir(priv->context);
+ if (!repos_dir[0]) {
+ g_warning("no repodir set");
+ return;
+ }
+ for (auto iter = repos_dir; *iter; ++iter) {
+ auto repo_dir = *iter;
+ dnf_repo_loader_setup_monitor(self, repo_dir, true);
+ }
+}
+
+/**
+ * dnf_repo_loader_new:
+ * @context: A #DnfContext instance
+ *
+ * Creates a new #DnfRepoLoader.
+ *
+ * Returns:(transfer full): a #DnfRepoLoader
+ *
+ * Since: 0.1.0
+ **/
+DnfRepoLoader *
+dnf_repo_loader_new(DnfContext *context)
+{
+ DnfRepoLoaderPrivate *priv;
+ auto self = DNF_REPO_LOADER(g_object_new(DNF_TYPE_REPO_LOADER, NULL));
+ priv = GET_PRIVATE(self);
+ priv->context = context;
+ g_object_add_weak_pointer(G_OBJECT(priv->context),(void **) &priv->context);
+ dnf_repo_loader_setup_watch(self);
+ return DNF_REPO_LOADER(self);
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_REPO_LOADER_H
+#define __DNF_REPO_LOADER_H
+
+#include <glib-object.h>
+#include "hy-repo.h"
+#include "hy-package.h"
+
+#include "dnf-context.h"
+#include "dnf-state.h"
+#include "dnf-repo.h"
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_REPO_LOADER (dnf_repo_loader_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfRepoLoader, dnf_repo_loader, DNF, REPO_LOADER, GObject)
+
+struct _DnfRepoLoaderClass
+{
+ GObjectClass parent_class;
+ void (* changed) (DnfRepoLoader *self);
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+DnfRepoLoader *dnf_repo_loader_new (DnfContext *context);
+
+/* object methods */
+gboolean dnf_repo_loader_has_removable_repos (DnfRepoLoader *self);
+GPtrArray *dnf_repo_loader_get_repos (DnfRepoLoader *self,
+ GError **error);
+DnfRepo *dnf_repo_loader_get_repo_by_id (DnfRepoLoader *self,
+ const gchar *id,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_REPO_LOADER_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Most of this code was taken from Zif, libzif/zif-repos.c
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+/**
+ * SECTION:dnf-repo
+ * @short_description: Object representing a remote repo.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * Sources are remote repositories of packages.
+ *
+ * See also: #DnfRepo
+ */
+
+#include "conf/OptionBool.hpp"
+
+#include "dnf-context.hpp"
+#include "hy-repo-private.hpp"
+#include "hy-iutil-private.hpp"
+
+#include <strings.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <glib/gstdio.h>
+#include "hy-util.h"
+#include <librepo/librepo.h>
+#include <rpm/rpmts.h>
+#include <librepo/yum.h>
+
+#include "catch-error.hpp"
+#include "dnf-keyring.h"
+#include "dnf-package.h"
+#include "dnf-repo.hpp"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+#include "utils/File.hpp"
+#include "utils/url-encode.hpp"
+#include "utils/utils.hpp"
+
+#include <set>
+#include <string>
+#include <vector>
+
+typedef struct
+{
+ DnfRepoEnabled enabled;
+ gchar **exclude_packages;
+ gchar *filename; /* /etc/yum.repos.d/updates.repo */
+ gchar *location; /* /var/cache/PackageKit/metadata/fedora */
+ gchar *location_tmp; /* /var/cache/PackageKit/metadata/fedora.tmp */
+ gchar *packages; /* /var/cache/PackageKit/metadata/fedora/packages */
+ gchar *packages_tmp; /* /var/cache/PackageKit/metadata/fedora.tmp/packages */
+ gchar *keyring; /* /var/cache/PackageKit/metadata/fedora/gpgdir */
+ gchar *keyring_tmp; /* /var/cache/PackageKit/metadata/fedora.tmp/gpgdir */
+ gint64 timestamp_generated; /* µs */
+ gint64 timestamp_modified; /* µs */
+ GError *last_check_error;
+ GKeyFile *keyfile;
+ DnfContext *context; /* weak reference */
+ DnfRepoKind kind;
+ libdnf::Repo *repo;
+ LrHandle *repo_handle;
+ LrResult *repo_result;
+ LrUrlVars *urlvars;
+ bool unit_test_mode; /* ugly hack for unit tests */
+} DnfRepoPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfRepo, dnf_repo, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfRepoPrivate *>(dnf_repo_get_instance_private (o)))
+
+/**
+ * dnf_repo_finalize:
+ **/
+static void
+dnf_repo_finalize(GObject *object)
+{
+ DnfRepo *repo = DNF_REPO(object);
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+
+ g_free(priv->filename);
+ g_strfreev(priv->exclude_packages);
+ g_free(priv->location_tmp);
+ g_free(priv->location);
+ g_free(priv->packages);
+ g_free(priv->packages_tmp);
+ g_free(priv->keyring);
+ g_free(priv->keyring_tmp);
+ g_clear_error(&priv->last_check_error);
+ if (priv->repo_result != NULL)
+ lr_result_free(priv->repo_result);
+ if (priv->repo_handle != NULL)
+ lr_handle_free(priv->repo_handle);
+ if (priv->repo != NULL)
+ hy_repo_free(priv->repo);
+ if (priv->keyfile != NULL)
+ g_key_file_unref(priv->keyfile);
+ if (priv->context != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->context),
+ (void **) &priv->context);
+
+ G_OBJECT_CLASS(dnf_repo_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_repo_init:
+ **/
+static void
+dnf_repo_init(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo = hy_repo_create("<preinit>");
+ priv->repo_handle = lr_handle_init();
+ priv->repo_result = lr_result_init();
+}
+
+/**
+ * dnf_repo_class_init:
+ **/
+static void
+dnf_repo_class_init(DnfRepoClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_repo_finalize;
+}
+
+/**
+ * dnf_repo_get_id:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo ID.
+ *
+ * Returns: the repo ID, e.g. "fedora-updates"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_repo_get_id(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return libdnf::repoGetImpl(priv->repo)->id.c_str();
+}
+
+/**
+ * dnf_repo_get_location:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo location.
+ *
+ * Returns: the repo location, e.g. "/var/cache/PackageKit/metadata/fedora"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_repo_get_location(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->location;
+}
+
+/**
+ * dnf_repo_get_filename:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo filename.
+ *
+ * Returns: the repo filename, e.g. "/etc/yum.repos.d/updates.repo"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_repo_get_filename(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->filename;
+}
+
+/**
+ * dnf_repo_get_packages:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo packages location.
+ *
+ * Returns: the repo packages location, e.g. "/var/cache/PackageKit/metadata/fedora/packages"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_repo_get_packages(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->packages;
+}
+
+/**
+ * dnf_repo_get_public_keys:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the public key location.
+ *
+ * Returns: (transfer full)(array zero-terminated=1): The repo public key location, e.g. "/var/cache/PackageKit/metadata/fedora/repomd.pub"
+ *
+ * Since: 0.8.2
+ **/
+gchar **
+dnf_repo_get_public_keys(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ const auto & keys = priv->repo->getConfig()->gpgkey().getValue();
+ gchar **ret = g_new0(gchar *, keys.size() + 1);
+ for (size_t i = 0; i < keys.size(); ++i) {
+ g_autofree gchar *key_bn = g_path_get_basename(keys[i].c_str());
+ ret[i] = g_build_filename(priv->location, key_bn, NULL);
+ }
+ return ret;
+}
+
+/**
+ * dnf_repo_substitute:
+ */
+static gchar *
+dnf_repo_substitute(DnfRepo *repo, const gchar *url)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ char *tmp;
+ gchar *substituted;
+
+ /* do a little dance so we can use g_free() rather than lr_free() */
+ tmp = lr_url_substitute(url, priv->urlvars);
+ substituted = g_strdup(tmp);
+ lr_free(tmp);
+
+ return substituted;
+}
+
+/**
+ * dnf_repo_get_description:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo description.
+ *
+ * Returns: the repo description, e.g. "Fedora 20 Updates"
+ *
+ * Since: 0.1.0
+ **/
+gchar *
+dnf_repo_get_description(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_autofree gchar *tmp = NULL;
+
+ /* is DVD */
+ if (priv->kind == DNF_REPO_KIND_MEDIA) {
+ tmp = g_key_file_get_string(priv->keyfile, "general", "name", NULL);
+ if (tmp == NULL)
+ return NULL;
+ } else {
+ tmp = g_key_file_get_string(priv->keyfile,
+ dnf_repo_get_id(repo),
+ "name",
+ NULL);
+ if (tmp == NULL)
+ return NULL;
+ }
+
+ /* have to substitute things like $releasever and $basearch */
+ return dnf_repo_substitute(repo, tmp);
+}
+
+/**
+ * dnf_repo_get_timestamp_generated:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: Time in seconds since the epoch (UTC)
+ **/
+guint64
+dnf_repo_get_timestamp_generated (DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->timestamp_generated;
+}
+
+/**
+ * dnf_repo_get_n_solvables:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: Number of packages in the repo
+ **/
+guint
+dnf_repo_get_n_solvables (DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return libdnf::repoGetImpl(priv->repo)->libsolvRepo->nsolvables;
+}
+
+/**
+ * dnf_repo_get_enabled:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets if the repo is enabled.
+ *
+ * Returns: %DNF_REPO_ENABLED_PACKAGES if enabled
+ *
+ * Since: 0.1.0
+ **/
+DnfRepoEnabled
+dnf_repo_get_enabled(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->enabled;
+}
+
+/**
+ * dnf_repo_get_required:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: %TRUE if failure fetching this repo is fatal
+ *
+ * Since: 0.2.1
+ **/
+gboolean
+dnf_repo_get_required(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return !priv->repo->getConfig()->skip_if_unavailable().getValue();
+}
+
+/**
+ * dnf_repo_get_cost:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo cost.
+ *
+ * Returns: the repo cost, where 1000 is default
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_repo_get_cost(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return repoGetImpl(priv->repo)->conf->cost().getValue();
+}
+
+/**
+ * dnf_repo_get_module_hotfixes:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo hotfixes flag for module RPMs filtering.
+ *
+ * Returns: the repo module_hotfixes flag, where false is default
+ *
+ * Since: 0.16.1
+ **/
+gboolean
+dnf_repo_get_module_hotfixes(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->repo->getConfig()->module_hotfixes().getValue();
+}
+
+/**
+ * dnf_repo_get_kind:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the repo kind.
+ *
+ * Returns: the repo kind, e.g. %DNF_REPO_KIND_MEDIA
+ *
+ * Since: 0.1.0
+ **/
+DnfRepoKind
+dnf_repo_get_kind(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->kind;
+}
+
+/**
+ * dnf_repo_get_exclude_packages:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns:(transfer none)(array zero-terminated=1): Packages which should be excluded
+ *
+ * Since: 0.1.9
+ **/
+gchar **
+dnf_repo_get_exclude_packages(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->exclude_packages;
+}
+
+/**
+ * dnf_repo_get_gpgcheck:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets if the packages should be signed.
+ *
+ * Returns: %TRUE if packages should be signed
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_get_gpgcheck(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->repo->getConfig()->gpgcheck().getValue();
+}
+
+/**
+ * dnf_repo_get_gpgcheck_md:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets if the metadata should be signed.
+ *
+ * Returns: %TRUE if metadata should be signed
+ *
+ * Since: 0.1.7
+ **/
+gboolean
+dnf_repo_get_gpgcheck_md(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->repo->getConfig()->repo_gpgcheck().getValue();
+}
+
+/**
+ * dnf_repo_get_repo:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the #HyRepo backing this repo.
+ *
+ * Returns: the #HyRepo
+ *
+ * Since: 0.1.0
+ **/
+HyRepo
+dnf_repo_get_repo(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->repo;
+}
+
+/**
+ * dnf_repo_get_metadata_expire:
+ * @repo: a #DnfRepo instance.
+ *
+ * Gets the metadata_expire time for the repo
+ *
+ * Returns: the metadata_expire time in seconds
+ */
+guint
+dnf_repo_get_metadata_expire(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ return priv->repo->getConfig()->metadata_expire().getValue();
+}
+
+/**
+ * dnf_repo_is_devel:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: %TRUE if the repo is a development repo
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_is_devel(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ auto repoId = priv->repo->getId().c_str();
+ if (g_str_has_suffix(repoId, "-debuginfo"))
+ return TRUE;
+ if (g_str_has_suffix(repoId, "-debug"))
+ return TRUE;
+ if (g_str_has_suffix(repoId, "-development"))
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * dnf_repo_is_local:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: %TRUE if the repo is a repo on local or media filesystem
+ *
+ * Since: 0.1.6
+ **/
+gboolean
+dnf_repo_is_local(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+
+ /* media or local */
+ if (priv->kind == DNF_REPO_KIND_MEDIA ||
+ priv->kind == DNF_REPO_KIND_LOCAL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * dnf_repo_is_source:
+ * @repo: a #DnfRepo instance.
+ *
+ * Returns: %TRUE if the repo is a source repo
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_is_source(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ if (g_str_has_suffix(priv->repo->getId().c_str(), "-source"))
+ return TRUE;
+ return FALSE;
+}
+
+/**
+ * dnf_repo_set_id:
+ * @repo: a #DnfRepo instance.
+ * @id: the ID, e.g. "fedora-updates"
+ *
+ * Sets the repo ID.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_id(DnfRepo *repo, const gchar *id)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ libdnf::repoGetImpl(priv->repo)->id = id;
+ libdnf::repoGetImpl(priv->repo)->conf->name().set(libdnf::Option::Priority::RUNTIME, id);
+}
+
+/**
+ * dnf_repo_set_location:
+ * @repo: a #DnfRepo instance.
+ * @location: the path
+ *
+ * Sets the repo location and the default packages path.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_location(DnfRepo *repo, const gchar *location)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_free(priv->location);
+ g_free(priv->packages);
+ g_free(priv->keyring);
+ priv->location = dnf_repo_substitute(repo, location);
+ priv->packages = g_build_filename(location, "packages", NULL);
+ priv->keyring = g_build_filename(location, "gpgdir", NULL);
+}
+
+/**
+ * dnf_repo_set_location_tmp:
+ * @repo: a #DnfRepo instance.
+ * @location_tmp: the temp path
+ *
+ * Sets the repo location for temporary files and the default packages path.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_location_tmp(DnfRepo *repo, const gchar *location_tmp)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_free(priv->location_tmp);
+ g_free(priv->packages_tmp);
+ g_free(priv->keyring_tmp);
+ priv->location_tmp = dnf_repo_substitute(repo, location_tmp);
+ priv->packages_tmp = g_build_filename(location_tmp, "packages", NULL);
+ priv->keyring_tmp = g_build_filename(location_tmp, "gpgdir", NULL);
+}
+
+/**
+ * dnf_repo_set_filename:
+ * @repo: a #DnfRepo instance.
+ * @filename: the filename path
+ *
+ * Sets the repo backing filename.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_filename(DnfRepo *repo, const gchar *filename)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+
+ g_free(priv->filename);
+ priv->filename = g_strdup(filename);
+}
+
+/**
+ * dnf_repo_set_packages:
+ * @repo: a #DnfRepo instance.
+ * @packages: the path to the package files
+ *
+ * Sets the repo package location, typically ending in "Packages" or "packages".
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_packages(DnfRepo *repo, const gchar *packages)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_free(priv->packages);
+ priv->packages = g_strdup(packages);
+}
+
+/**
+ * dnf_repo_set_packages_tmp:
+ * @repo: a #DnfRepo instance.
+ * @packages_tmp: the path to the temporary package files
+ *
+ * Sets the repo package location for temporary files.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_packages_tmp(DnfRepo *repo, const gchar *packages_tmp)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_free(priv->packages_tmp);
+ priv->packages_tmp = g_strdup(packages_tmp);
+}
+
+/**
+ * dnf_repo_set_enabled:
+ * @repo: a #DnfRepo instance.
+ * @enabled: if the repo is enabled
+ *
+ * Sets the repo enabled state.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_enabled(DnfRepo *repo, DnfRepoEnabled enabled)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+
+ priv->enabled = enabled;
+
+ /* packages implies metadata */
+ if (priv->enabled & DNF_REPO_ENABLED_PACKAGES)
+ priv->enabled |= DNF_REPO_ENABLED_METADATA;
+}
+
+/**
+ * dnf_repo_set_required:
+ * @repo: a #DnfRepo instance.
+ * @required: if the repo is required
+ *
+ * Sets whether failure to retrieve the repo is fatal; by default it
+ * is not.
+ *
+ * Since: 0.2.1
+ **/
+void
+dnf_repo_set_required(DnfRepo *repo, gboolean required)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->skip_if_unavailable().set(libdnf::Option::Priority::RUNTIME, !required);
+}
+
+/**
+ * dnf_repo_set_cost:
+ * @repo: a #DnfRepo instance.
+ * @cost: the repo cost
+ *
+ * Sets the repo cost, where 1000 is the default.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_cost(DnfRepo *repo, guint cost)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ repoGetImpl(priv->repo)->conf->cost().set(libdnf::Option::Priority::RUNTIME, cost);
+}
+
+/**
+ * dnf_repo_set_module_hotfixes:
+ * @repo: a #DnfRepo instance.
+ * @module_hotfixes: hotfixes flag for module RPMs filtering
+ *
+ * Sets the repo hotfixes flag for module RPMs filtering.
+ *
+ * Since: 0.16.1
+ **/
+void
+dnf_repo_set_module_hotfixes(DnfRepo *repo, gboolean module_hotfixes)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->module_hotfixes().set(libdnf::Option::Priority::RUNTIME, module_hotfixes);
+}
+
+/**
+ * dnf_repo_set_kind:
+ * @repo: a #DnfRepo instance.
+ * @kind: the #DnfRepoKind
+ *
+ * Sets the repo kind.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_kind(DnfRepo *repo, DnfRepoKind kind)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->kind = kind;
+}
+
+/**
+ * dnf_repo_set_gpgcheck:
+ * @repo: a #DnfRepo instance.
+ * @gpgcheck_pkgs: if the repo packages should be signed
+ *
+ * Sets the repo signed status.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_gpgcheck(DnfRepo *repo, gboolean gpgcheck_pkgs)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->gpgcheck().set(libdnf::Option::Priority::RUNTIME, gpgcheck_pkgs);
+}
+
+/**
+ * dnf_repo_set_skip_if_unavailiable:
+ * @repo: a #DnfRepo instance.
+ * @skip_if_unavailable: whether the repo should be skipped if unavailable
+ *
+ * Sets the repo skip_if_unavailable status
+ *
+ * Since: 0.7.3
+ **/
+void
+dnf_repo_set_skip_if_unavailable(DnfRepo *repo, gboolean skip_if_unavailable)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->skip_if_unavailable().set(libdnf::Option::Priority::RUNTIME, skip_if_unavailable);
+}
+
+/**
+ * dnf_repo_set_gpgcheck_md:
+ * @repo: a #DnfRepo instance.
+ * @gpgcheck_md: if the repo metadata should be signed
+ *
+ * Sets the metadata signed status.
+ *
+ * Since: 0.1.7
+ **/
+void
+dnf_repo_set_gpgcheck_md(DnfRepo *repo, gboolean gpgcheck_md)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->repo_gpgcheck().set(libdnf::Option::Priority::RUNTIME, gpgcheck_md);
+}
+
+/**
+ * dnf_repo_set_keyfile:
+ * @repo: a #DnfRepo instance.
+ * @keyfile: the #GKeyFile
+ *
+ * Sets the repo keyfile used to create the repo.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_repo_set_keyfile(DnfRepo *repo, GKeyFile *keyfile)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ if (priv->keyfile != NULL)
+ g_key_file_unref(priv->keyfile);
+ priv->keyfile = g_key_file_ref(keyfile);
+}
+
+/**
+ * dnf_repo_set_metadata_expire:
+ * @repo: a #DnfRepo instance.
+ * @metadata_expire: the expected expiry time for metadata
+ *
+ * Sets the metadata_expire time, which defaults to 48h.
+ **/
+void
+dnf_repo_set_metadata_expire(DnfRepo *repo, guint metadata_expire)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ priv->repo->getConfig()->metadata_expire().set(libdnf::Option::Priority::RUNTIME, metadata_expire);
+}
+
+/**
+* @brief Format user password string
+*
+* Returns user and password in user:password form. If encode is True,
+* special characters in user and password are URL encoded.
+*
+* @param user Username
+* @param passwd Password
+* @param encode If quote is True, special characters in user and password are URL encoded.
+* @return User and password in user:password form
+*/
+static std::string formatUserPassString(const std::string & user, const std::string & passwd, bool encode)
+{
+ if (encode)
+ return libdnf::urlEncode(user) + ":" + libdnf::urlEncode(passwd);
+ else
+ return user + ":" + passwd;
+}
+
+/* Resets repository configuration options previously readed from repository
+ * configuration file to initial state. */
+static void
+dnf_repo_conf_reset(libdnf::ConfigRepo &config)
+{
+ for (auto & item : config.optBinds()) {
+ auto & itemOption = item.second;
+ if (itemOption.getPriority() == libdnf::Option::Priority::REPOCONFIG) {
+ itemOption.getOption().reset();
+ }
+ }
+}
+
+/* Loads repository configuration from GKeyFile */
+static void
+dnf_repo_conf_from_gkeyfile(DnfRepo *repo, const char *repoId, GKeyFile *gkeyFile)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ auto & config = *priv->repo->getConfig();
+
+ // Reset to the initial state before reloading the configuration.
+ dnf_repo_conf_reset(config);
+
+ g_autoptr(GError) error_local = NULL;
+ g_auto(GStrv) keys = g_key_file_get_keys(gkeyFile, repoId, NULL, &error_local);
+ if (keys == NULL) {
+ g_debug("Failed to load configuration for repo id \"%s\": %s", repoId, error_local->message);
+ return;
+ }
+
+ for (auto it = keys; *it != NULL; ++it) {
+ auto key = *it;
+ g_autofree gchar *str = g_key_file_get_value(gkeyFile, repoId, key, NULL);
+ if (str) {
+ auto value = libdnf::string::trim(str);
+ if (value.length() > 1 && value.front() == value.back() &&
+ (value.front() == '"' || value.front() == '\'')) {
+ value.erase(--value.end());
+ value.erase(value.begin());
+ }
+ try {
+ auto & optionItem = config.optBinds().at(key);
+
+ if (dynamic_cast<libdnf::OptionStringList*>(&optionItem.getOption()) ||
+ dynamic_cast<libdnf::OptionChild<libdnf::OptionStringList>*>(&optionItem.getOption())
+ ) {
+
+ // reload list option from gKeyFile using g_key_file_get_string_list()
+ // g_key_file_get_value () is problematic for multiline lists
+ g_auto(GStrv) list = g_key_file_get_string_list(gkeyFile, repoId, key, NULL, NULL);
+ if (list) {
+ // list can be ['value1', 'value2, value3'] therefore we first join
+ // to have 'value1, value2, value3'
+ g_autofree gchar * tmp_strval = g_strjoinv(",", list);
+
+ // Substitute vars.
+ g_autofree gchar *subst_value = dnf_repo_substitute(repo, tmp_strval);
+
+ if (strcmp(key, "baseurl") == 0 && strstr(tmp_strval, "file://$testdatadir") != NULL) {
+ priv->unit_test_mode = true;
+ }
+
+ try {
+ optionItem.newString(libdnf::Option::Priority::REPOCONFIG, subst_value);
+ } catch (const std::exception & ex) {
+ g_debug("Invalid configuration value: %s = %s in %s; %s", key, subst_value, repoId, ex.what());
+ }
+ }
+
+ } else {
+ // process other (non list) options
+
+ // Substitute vars.
+ g_autofree gchar *subst_value = dnf_repo_substitute(repo, value.c_str());
+
+ try {
+ optionItem.newString(libdnf::Option::Priority::REPOCONFIG, subst_value);
+ } catch (const std::exception & ex) {
+ g_debug("Invalid configuration value: %s = %s in %s; %s", key, subst_value, repoId, ex.what());
+ }
+
+ }
+
+ } catch (const std::exception &) {
+ g_debug("Unknown configuration option: %s = %s in %s", key, value.c_str(), repoId);
+ }
+ }
+ }
+}
+
+static void
+dnf_repo_apply_setopts(libdnf::ConfigRepo &config, const char *repoId)
+{
+ // apply repository setopts
+ auto & optBinds = config.optBinds();
+ for (const auto & setopt : libdnf::getGlobalSetopts()) {
+ auto last_dot_pos = setopt.key.rfind('.');
+ if (last_dot_pos == std::string::npos) {
+ continue;
+ }
+ auto repo_pattern = setopt.key.substr(0, last_dot_pos);
+ if (fnmatch(repo_pattern.c_str(), repoId, FNM_CASEFOLD) == 0) {
+ auto key = setopt.key.substr(last_dot_pos+1);
+ try {
+ auto & optionItem = optBinds.at(key);
+ try {
+ optionItem.newString(setopt.priority, setopt.value);
+ } catch (const std::exception & ex) {
+ g_warning("dnf_repo_apply_setopt: Invalid configuration value: %s = %s; %s", setopt.key.c_str(), setopt.value.c_str(), ex.what());
+ }
+ } catch (const std::exception &) {
+ g_warning("dnf_repo_apply_setopt: Unknown configuration option: %s in %s = %s", key.c_str(), setopt.key.c_str(), setopt.value.c_str());
+ }
+ }
+ }
+}
+
+/* Initialize (or potentially reset) repo & LrHandle from keyfile values. */
+static gboolean
+dnf_repo_set_keyfile_data(DnfRepo *repo, gboolean reloadFromGKeyFile, GError **error)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ std::string tmp_str;
+ const char *tmp_cstr;
+
+ auto repoId = priv->repo->getId().c_str();
+ g_debug("setting keyfile data for %s", repoId);
+
+ auto conf = priv->repo->getConfig();
+
+ // Reload repository configuration from keyfile.
+ if (reloadFromGKeyFile) {
+ dnf_repo_conf_from_gkeyfile(repo, repoId, priv->keyfile);
+ dnf_repo_apply_setopts(*conf, repoId);
+ }
+
+ if (dnf_context_get_cache_dir(priv->context))
+ conf->basecachedir().set(libdnf::Option::Priority::REPOCONFIG, dnf_context_get_cache_dir(priv->context));
+
+ /* baseurl is optional; if missing, unset it */
+ g_auto(GStrv) baseurls = NULL;
+ auto & repoBaseurls = conf->baseurl().getValue();
+ if (!repoBaseurls.empty()){
+ auto len = repoBaseurls.size();
+ baseurls = g_new0(char *, len + 1);
+ for (size_t i = 0; i < len; ++i) {
+ baseurls[i] = g_strdup(repoBaseurls[i].c_str());
+ }
+ }
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_URLS, baseurls))
+ return FALSE;
+
+ const char *mirrorlisturl = NULL;
+ const char *metalinkurl = NULL;
+
+ /* the "mirrorlist" entry could be either a real mirrorlist, or a metalink entry */
+ tmp_cstr = conf->mirrorlist().empty() ? NULL : conf->mirrorlist().getValue().c_str();
+ if (tmp_cstr) {
+ if (strstr(tmp_cstr, "metalink"))
+ metalinkurl = tmp_cstr;
+ else /* it really is a mirrorlist */
+ mirrorlisturl = tmp_cstr;
+ }
+
+ /* let "metalink" entry override metalink-as-mirrorlist entry */
+ tmp_cstr = conf->metalink().empty() ? NULL : conf->metalink().getValue().c_str();
+ if (tmp_cstr)
+ metalinkurl = tmp_cstr;
+
+ /* now set the final values (or unset them) */
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_MIRRORLISTURL, mirrorlisturl))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_METALINKURL, metalinkurl))
+ return FALSE;
+
+ /* file:// */
+ if (baseurls != NULL && baseurls[0] != NULL &&
+ mirrorlisturl == NULL && metalinkurl == NULL) {
+ g_autofree gchar *url = NULL;
+ url = lr_prepend_url_protocol(baseurls[0]);
+ if (url != NULL && strncasecmp(url, "file://", 7) == 0) {
+ if (!priv->unit_test_mode) {
+ priv->kind = DNF_REPO_KIND_LOCAL;
+ }
+ g_free(priv->location);
+ g_free(priv->keyring);
+ priv->location = dnf_repo_substitute(repo, url + 7);
+ priv->keyring = g_build_filename(url + 7, "gpgdir", NULL);
+ }
+ }
+
+ /* set location if currently unset */
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOCAL, 0L))
+ return FALSE;
+
+ /* set repos cache dir */
+ g_autofree gchar *cache_path = NULL;
+ /* make each repo's cache directory name has releasever and basearch as its suffix */
+ g_autofree gchar *cache_file_name = g_strjoin("-", repoId,
+ dnf_context_get_release_ver(priv->context),
+ dnf_context_get_base_arch(priv->context), NULL);
+
+ cache_path = g_build_filename(dnf_context_get_cache_dir(priv->context), cache_file_name, NULL);
+ if (priv->packages == NULL) {
+ g_autofree gchar *packages_path = g_build_filename(cache_path, "packages", NULL);
+ dnf_repo_set_packages(repo, packages_path);
+ }
+ if (priv->location == NULL) {
+ dnf_repo_set_location(repo, cache_path);
+ }
+
+ /* set temp location used for updating remote repos */
+ if (priv->kind == DNF_REPO_KIND_REMOTE) {
+ g_autoptr(GString) tmp = NULL;
+ tmp = g_string_new(priv->location);
+ if (tmp->len > 0 && tmp->str[tmp->len - 1] == '/')
+ g_string_truncate(tmp, tmp->len - 1);
+ g_string_append(tmp, ".tmp");
+ dnf_repo_set_location_tmp(repo, tmp->str);
+ }
+
+ /* gpgkey is optional for gpgcheck=1, but required for repo_gpgcheck=1 */
+ auto repo_gpgcheck = conf->repo_gpgcheck().getValue();
+ if (repo_gpgcheck && conf->gpgkey().getValue().empty()) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ "gpgkey not set, yet repo_gpgcheck=1");
+ return FALSE;
+ }
+
+ /* XXX: setopt() expects a long, so we need a long on the stack */
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_GPGCHECK, (long)repo_gpgcheck))
+ return FALSE;
+
+ // Sync priv->exclude_packages
+ g_strfreev(priv->exclude_packages);
+ auto & repoExcludepkgs = conf->excludepkgs().getValue();
+ if (!repoExcludepkgs.empty()) {
+ auto len = repoExcludepkgs.size();
+ priv->exclude_packages = g_new0(char *, len + 1);
+ for (size_t i = 0; i < len; ++i) {
+ priv->exclude_packages[i] = g_strdup(repoExcludepkgs[i].c_str());
+ }
+ } else {
+ priv->exclude_packages = NULL;
+ }
+
+ auto minrate = conf->minrate().getValue();
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDLIMIT, static_cast<long>(minrate)))
+ return FALSE;
+
+ auto maxspeed = conf->throttle().getValue();
+ if (maxspeed > 0 && maxspeed <= 1)
+ maxspeed *= conf->bandwidth().getValue();
+ if (maxspeed != 0 && maxspeed < minrate) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FILE_INVALID,
+ "Maximum download speed is lower than minimum. "
+ "Please change configuration of minrate or throttle");
+ return FALSE;
+ }
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_MAXSPEED, static_cast<int64_t>(maxspeed)))
+ return FALSE;
+
+ long timeout = conf->timeout().getValue();
+ if (timeout > 0) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_CONNECTTIMEOUT, timeout))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDTIME, timeout))
+ return FALSE;
+ } else {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_CONNECTTIMEOUT, LRO_CONNECTTIMEOUT_DEFAULT))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOWSPEEDTIME, LRO_LOWSPEEDTIME_DEFAULT))
+ return FALSE;
+ }
+
+ tmp_str = conf->proxy().getValue();
+ tmp_cstr = tmp_str.empty() ? dnf_context_get_http_proxy(priv->context) : tmp_str.c_str();
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY, tmp_cstr))
+ return FALSE;
+
+ // setup proxy authorization method
+ auto proxyAuthMethods = libdnf::Repo::Impl::stringToProxyAuthMethods(conf->proxy_auth_method().getValue());
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXYAUTHMETHODS, static_cast<long>(proxyAuthMethods)))
+ return FALSE;
+
+ // setup proxy username and password
+ tmp_cstr = NULL;
+ if (!conf->proxy_username().empty()) {
+ tmp_str = conf->proxy_username().getValue();
+ if (!tmp_str.empty()) {
+ if (conf->proxy_password().empty()) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID,
+ "repo '%s': 'proxy_username' is set but not 'proxy_password'", repoId);
+ return FALSE;
+ }
+ tmp_str = formatUserPassString(tmp_str, conf->proxy_password().getValue(), true);
+ tmp_cstr = tmp_str.c_str();
+ }
+ }
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXYUSERPWD, tmp_cstr))
+ return FALSE;
+
+ // setup username and password
+ tmp_cstr = NULL;
+ tmp_str = conf->username().getValue();
+ if (!tmp_str.empty()) {
+ // TODO Use URL encoded form, needs support in librepo
+ tmp_str = formatUserPassString(tmp_str, conf->password().getValue(), false);
+ tmp_cstr = tmp_str.c_str();
+ }
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_USERPWD, tmp_cstr))
+ return FALSE;
+
+ auto proxy_sslverify = conf->proxy_sslverify().getValue();
+ /* XXX: setopt() expects a long, so we need a long on the stack */
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY_SSLVERIFYPEER, (long)proxy_sslverify))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY_SSLVERIFYHOST, (long)proxy_sslverify))
+ return FALSE;
+
+ auto & proxy_sslcacert = conf->proxy_sslcacert().getValue();
+ if (!proxy_sslcacert.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY_SSLCACERT, proxy_sslcacert.c_str()))
+ return FALSE;
+ }
+
+ auto & proxy_sslclientcert = conf->proxy_sslclientcert().getValue();
+ if (!proxy_sslclientcert.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY_SSLCLIENTCERT, proxy_sslclientcert.c_str()))
+ return FALSE;
+ }
+
+ auto & proxy_sslclientkey = conf->proxy_sslclientkey().getValue();
+ if (!proxy_sslclientkey.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_PROXY_SSLCLIENTKEY, proxy_sslclientkey.c_str()))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * dnf_repo_setup:
+ * @repo: a #DnfRepo instance.
+ * @error: a #GError or %NULL
+ *
+ * Sets up the repo ready for use.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_setup(DnfRepo *repo, GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ DnfRepoEnabled enabled = DNF_REPO_ENABLED_NONE;
+ g_autofree gchar *basearch = NULL;
+ g_autofree gchar *release = NULL;
+
+ basearch = g_key_file_get_string(priv->keyfile, "general", "arch", NULL);
+ if (basearch == NULL)
+ basearch = g_strdup(dnf_context_get_base_arch(priv->context));
+ if (basearch == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "basearch not set");
+ return FALSE;
+ }
+ release = g_key_file_get_string(priv->keyfile, "general", "version", NULL);
+ if (release == NULL)
+ release = g_strdup(dnf_context_get_release_ver(priv->context));
+ if (release == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "releasever not set");
+ return FALSE;
+ }
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_USERAGENT, dnf_context_get_user_agent(priv->context)))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_REPOTYPE, LR_YUMREPO))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_INTERRUPTIBLE, 0L))
+ return FALSE;
+ priv->urlvars = lr_urlvars_set(priv->urlvars, "releasever", release);
+ priv->urlvars = lr_urlvars_set(priv->urlvars, "basearch", basearch);
+
+ /* Call libdnf::dnf_context_load_vars(priv->context); only when values not in cache.
+ * But what about if variables on disk change during long running programs (PackageKit daemon)?
+ * if (!libdnf::dnf_context_get_vars_cached(priv->context))
+ */
+ libdnf::dnf_context_load_vars(priv->context);
+ for (const auto & item : libdnf::dnf_context_get_vars(priv->context))
+ priv->urlvars = lr_urlvars_set(priv->urlvars, item.first.c_str(), item.second.c_str());
+
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_VARSUB, priv->urlvars))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_GNUPGHOMEDIR, priv->keyring))
+ return FALSE;
+
+ auto repoId = priv->repo->getId().c_str();
+
+ auto conf = priv->repo->getConfig();
+ dnf_repo_conf_from_gkeyfile(repo, repoId, priv->keyfile);
+ dnf_repo_apply_setopts(*conf, repoId);
+
+ auto sslverify = conf->sslverify().getValue();
+ /* XXX: setopt() expects a long, so we need a long on the stack */
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLVERIFYPEER, (long)sslverify))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLVERIFYHOST, (long)sslverify))
+ return FALSE;
+
+ auto & sslcacert = conf->sslcacert().getValue();
+ if (!sslcacert.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLCACERT, sslcacert.c_str()))
+ return FALSE;
+ }
+
+ auto & sslclientcert = conf->sslclientcert().getValue();
+ if (!sslclientcert.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLCLIENTCERT, sslclientcert.c_str()))
+ return FALSE;
+ }
+
+ auto & sslclientkey = conf->sslclientkey().getValue();
+ if (!sslclientkey.empty()) {
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLCLIENTKEY, sslclientkey.c_str()))
+ return FALSE;
+ }
+
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_SSLVERIFYSTATUS, conf->sslverifystatus().getValue() ? 1L : 0L))
+ return FALSE;
+
+#ifdef LRO_SUPPORTS_CACHEDIR
+ /* Set cache dir */
+ if (dnf_context_get_zchunk(priv->context)) {
+ if(!lr_handle_setopt(priv->repo_handle, error, LRO_CACHEDIR, dnf_context_get_cache_dir(priv->context)))
+ return FALSE;
+ }
+#endif
+
+ if (conf->enabled().getValue())
+ enabled |= DNF_REPO_ENABLED_PACKAGES;
+
+ /* enabled_metadata is optional */
+ if (conf->enabled_metadata().getPriority() != libdnf::Option::Priority::DEFAULT) {
+ try {
+ if (libdnf::OptionBool(false).fromString(conf->enabled_metadata().getValue()))
+ enabled |= DNF_REPO_ENABLED_METADATA;
+ } catch (const std::exception & ex) {
+ g_warning("Config error in section \"%s\" key \"%s\": %s", repoId, "enabled_metadata", ex.what());
+ }
+ } else {
+ g_autofree gchar *basename = g_path_get_basename(priv->filename);
+ /* special case the satellite and subscription manager repo */
+ if (g_strcmp0(basename, "redhat.repo") == 0)
+ enabled |= DNF_REPO_ENABLED_METADATA;
+ }
+
+ dnf_repo_set_enabled(repo, enabled);
+
+ return dnf_repo_set_keyfile_data(repo, FALSE, error);
+} CATCH_TO_GERROR(FALSE)
+
+typedef struct
+{
+ DnfState *state;
+ gchar *last_mirror_url;
+ gchar *last_mirror_failure_message;
+} RepoUpdateData;
+
+/**
+ * dnf_repo_update_state_cb:
+ */
+static int
+dnf_repo_update_state_cb(void *user_data,
+ gdouble total_to_download,
+ gdouble now_downloaded)
+{
+ gboolean ret;
+ gdouble percentage;
+ auto updatedata = static_cast<RepoUpdateData *>(user_data);
+ DnfState *state = updatedata->state;
+
+ /* abort */
+ if (!dnf_state_check(state, NULL))
+ return -1;
+
+ /* the number of files has changed */
+ if (total_to_download <= 0.01 && now_downloaded <= 0.01) {
+ dnf_state_reset(state);
+ return 0;
+ }
+
+ /* nothing sensible */
+ if (total_to_download < 0)
+ return 0;
+
+ /* set percentage */
+ percentage = 100.0f * now_downloaded / total_to_download;
+ ret = dnf_state_set_percentage(state, percentage);
+ if (ret) {
+ g_debug("update state %.0f/%.0f",
+ now_downloaded,
+ total_to_download);
+ }
+
+ return 0;
+}
+
+/**
+ * dnf_repo_set_timestamp_modified:
+ */
+static gboolean
+dnf_repo_set_timestamp_modified(DnfRepo *repo, GError **error)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_autofree gchar *filename = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GFileInfo) info = NULL;
+
+ filename = g_build_filename(priv->location, "repodata", "repomd.xml", NULL);
+ file = g_file_new_for_path(filename);
+ info = g_file_query_info(file,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ error);
+ if (info == NULL)
+ return FALSE;
+ priv->timestamp_modified = g_file_info_get_attribute_uint64(info,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED) * G_USEC_PER_SEC;
+ priv->timestamp_modified += g_file_info_get_attribute_uint32(info,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
+ return TRUE;
+}
+
+static gboolean
+dnf_repo_check_internal(DnfRepo *repo,
+ guint permissible_cache_age,
+ DnfState *state,
+ GError **error)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ auto repoImpl = libdnf::repoGetImpl(priv->repo);
+
+ std::vector<const char *> download_list = {"primary", "group", "updateinfo", "appstream",
+ "appstream-icons", "modules"};
+ /* This one is huge, and at least rpm-ostree jigdo mode doesn't require it.
+ * https://github.com/projectatomic/rpm-ostree/issues/1127
+ */
+ if (dnf_context_get_enable_filelists(priv->context))
+ download_list.push_back("filelists");
+ for (const auto & item : repoImpl->additionalMetadata) {
+ download_list.push_back(item.c_str());
+ }
+ download_list.push_back(NULL);
+ gboolean ret;
+ LrYumRepo *yum_repo;
+ const gchar *urls[] = { "", NULL };
+ gint64 age_of_data; /* in seconds */
+ g_autoptr(GError) error_local = NULL;
+ guint metadata_expire;
+ guint valid_time_allowed;
+
+ /* has the media repo vanished? */
+ if (priv->kind == DNF_REPO_KIND_MEDIA &&
+ !g_file_test(priv->location, G_FILE_TEST_EXISTS)) {
+ if (!dnf_repo_get_required(repo))
+ priv->enabled = DNF_REPO_ENABLED_NONE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_AVAILABLE,
+ "%s was not found", priv->location);
+ return FALSE;
+ }
+
+ /* has the local repo vanished? */
+ if (priv->kind == DNF_REPO_KIND_LOCAL &&
+ !g_file_test(priv->location, G_FILE_TEST_EXISTS)) {
+ if (!dnf_repo_get_required(repo))
+ priv->enabled = DNF_REPO_ENABLED_NONE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_AVAILABLE,
+ "%s was not found", priv->location);
+ return FALSE;
+ }
+
+ /* Yum metadata */
+ dnf_state_action_start(state, DNF_STATE_ACTION_LOADING_CACHE, NULL);
+ urls[0] = priv->location;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_URLS, urls))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_DESTDIR, priv->location))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_LOCAL, 1L))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_CHECKSUM, 1L))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_YUMDLIST, download_list.data()))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_MIRRORLISTURL, NULL))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_METALINKURL, NULL))
+ return FALSE;
+ if (!lr_handle_setopt(priv->repo_handle, error, LRO_GNUPGHOMEDIR, priv->keyring))
+ return FALSE;
+ lr_result_clear(priv->repo_result);
+ if (!lr_handle_perform(priv->repo_handle, priv->repo_result, &error_local)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_AVAILABLE,
+ "repodata %s was not complete: %s",
+ priv->repo->getId().c_str(), error_local->message);
+ return FALSE;
+ }
+
+ /* get the metadata file locations */
+ if (!lr_result_getinfo(priv->repo_result, &error_local, LRR_YUM_REPO, &yum_repo)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to get yum-repo: %s",
+ error_local->message);
+ return FALSE;
+ }
+ repoImpl->repomdFn = yum_repo->repomd;
+
+ /* get timestamp */
+ ret = lr_result_getinfo(priv->repo_result, &error_local,
+ LRR_YUM_TIMESTAMP, &priv->timestamp_generated);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to get timestamp: %s",
+ error_local->message);
+ return FALSE;
+ }
+
+ /* check metadata age for non-local repos */
+ if (priv->kind != DNF_REPO_KIND_LOCAL && permissible_cache_age != G_MAXUINT) {
+ if (!dnf_repo_set_timestamp_modified(repo, error))
+ return FALSE;
+ age_of_data =(g_get_real_time() - priv->timestamp_modified) / G_USEC_PER_SEC;
+
+ /* choose a lower value between cache and metadata_expire for expired checking */
+ metadata_expire = dnf_repo_get_metadata_expire(repo);
+ valid_time_allowed = (metadata_expire <= permissible_cache_age ? metadata_expire : permissible_cache_age);
+
+ if (age_of_data > valid_time_allowed) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "cache too old: %" G_GINT64_FORMAT" > %i",
+ age_of_data, valid_time_allowed);
+ return FALSE;
+ }
+ }
+
+ /* init newRepo */
+ auto newRepo = hy_repo_create(priv->repo->getId().c_str());
+ auto newRepoImpl = libdnf::repoGetImpl(newRepo);
+
+ // "additionalMetadata" are not part of the config. They are filled during runtime
+ // (eg. by plugins) and must be kept.
+ newRepoImpl->additionalMetadata = repoImpl->additionalMetadata;
+
+ hy_repo_free(priv->repo);
+ priv->repo = newRepo;
+ newRepoImpl->repomdFn = yum_repo->repomd;
+ for (auto *elem = yum_repo->paths; elem; elem = g_slist_next(elem)) {
+ if (elem->data) {
+ auto yumrepopath = static_cast<LrYumRepoPath *>(elem->data);
+ newRepoImpl->metadataPaths[yumrepopath->type] = yumrepopath->path;
+ }
+ }
+ /* ensure we reset the values from the keyfile */
+ if (!dnf_repo_set_keyfile_data(repo, TRUE, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * dnf_repo_check:
+ * @repo: a #DnfRepo instance.
+ * @permissible_cache_age: The oldest cache age allowed in seconds(wall clock time); Pass %G_MAXUINT to ignore
+ * @state: a #DnfState instance.
+ * @error: a #GError or %NULL.
+ *
+ * Checks the repo.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_check(DnfRepo *repo,
+ guint permissible_cache_age,
+ DnfState *state,
+ GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_clear_error(&priv->last_check_error);
+ if (!dnf_repo_check_internal(repo, permissible_cache_age, state,
+ &priv->last_check_error)) {
+ if (error)
+ *error = g_error_copy(priv->last_check_error);
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+
+/**
+ * dnf_repo_get_filename_md:
+ * @repo: a #DnfRepo instance.
+ * @md_kind: The file kind, e.g. "primary" or "updateinfo"
+ *
+ * Gets the filename used for a repo data kind.
+ *
+ * Returns: the full path to the data file, %NULL otherwise
+ *
+ * Since: 0.1.7
+ **/
+const gchar *
+dnf_repo_get_filename_md(DnfRepo *repo, const gchar *md_kind)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_return_val_if_fail(md_kind != NULL, NULL);
+ if (priv->repo) {
+ auto repoImpl = libdnf::repoGetImpl(priv->repo);
+ auto & filename = repoImpl->getMetadataPath(md_kind);
+ return filename.empty() ? nullptr : filename.c_str();
+ } else
+ return nullptr;
+}
+
+/**
+ * dnf_repo_clean:
+ * @repo: a #DnfRepo instance.
+ * @error: a #GError or %NULL.
+ *
+ * Cleans the repo by deleting all the location contents.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_clean(DnfRepo *repo, GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+
+ /* do not clean media or local repos */
+ if (priv->kind == DNF_REPO_KIND_MEDIA ||
+ priv->kind == DNF_REPO_KIND_LOCAL)
+ return TRUE;
+
+ if (!g_file_test(priv->location, G_FILE_TEST_EXISTS))
+ return TRUE;
+ if (!dnf_remove_recursive(priv->location, error))
+ return FALSE;
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_repo_add_public_key:
+ *
+ * This imports a repodata public key into the default librpm keyring
+ **/
+static gboolean
+dnf_repo_add_public_key(DnfRepo *repo,
+ const char *tmp_path,
+ GError **error)
+{
+ gboolean ret;
+ rpmKeyring keyring;
+ rpmts ts;
+
+ /* then import to rpmdb */
+ ts = rpmtsCreate();
+ keyring = rpmtsGetKeyring(ts, 1);
+ ret = dnf_keyring_add_public_key(keyring, tmp_path, error);
+ rpmKeyringFree(keyring);
+ rpmtsFree(ts);
+ return ret;
+}
+
+/**
+ * dnf_repo_download_import_public_keys:
+ **/
+static gboolean
+dnf_repo_download_import_public_key(DnfRepo *repo,
+ const char *gpgkey,
+ const char *key_tmp,
+ GError **error)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ int fd;
+ g_autoptr(GError) error_local = NULL;
+
+ /* does this file already exist */
+ if (g_file_test(key_tmp, G_FILE_TEST_EXISTS))
+ return lr_gpg_import_key(key_tmp, priv->keyring_tmp, error);
+
+ /* create the gpgdir location */
+ if (g_mkdir_with_parents(priv->keyring_tmp, 0755) != 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Failed to create %s",
+ priv->keyring_tmp);
+ return FALSE;
+ }
+
+ /* set the keyring location */
+ if (!lr_handle_setopt(priv->repo_handle, error,
+ LRO_GNUPGHOMEDIR, priv->keyring_tmp))
+ return FALSE;
+
+ /* download to known location */
+ g_debug("Downloading %s to %s", gpgkey, key_tmp);
+ fd = g_open(key_tmp, O_CLOEXEC | O_CREAT | O_RDWR, 0774);
+ if (fd < 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Failed to open %s: %i",
+ key_tmp, fd);
+ return FALSE;
+ }
+ if (!lr_download_url(priv->repo_handle, gpgkey, fd, &error_local)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_FETCH_SOURCE,
+ "Failed to download gpg key for repo '%s': %s",
+ dnf_repo_get_id(repo),
+ error_local->message);
+ g_close(fd, NULL);
+ return FALSE;
+ }
+ if (!g_close(fd, error))
+ return FALSE;
+
+ /* import found key */
+ return lr_gpg_import_key(key_tmp, priv->keyring_tmp, error);
+}
+
+static int
+repo_mirrorlist_failure_cb(void *user_data,
+ const char *message,
+ const char *url,
+ const char *metadata)
+{
+ auto data = static_cast<RepoUpdateData *>(user_data);
+
+ if (data->last_mirror_url)
+ goto out;
+
+ data->last_mirror_url = g_strdup(url);
+ data->last_mirror_failure_message = g_strdup(message);
+ out:
+ return LR_CB_OK;
+}
+
+/**
+ * dnf_repo_update:
+ * @repo: a #DnfRepo instance.
+ * @flags: #DnfRepoUpdateFlags, e.g. %DNF_REPO_UPDATE_FLAG_FORCE
+ * @state: a #DnfState instance.
+ * @error: a #%GError or %NULL.
+ *
+ * Updates the repo.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_update(DnfRepo *repo,
+ DnfRepoUpdateFlags flags,
+ DnfState *state,
+ GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ DnfState *state_local;
+ gboolean ret;
+ gint rc;
+ gint64 timestamp_new = 0;
+ g_autoptr(GError) error_local = NULL;
+ RepoUpdateData updatedata = { 0, };
+
+ /* cannot change DVD contents */
+ if (priv->kind == DNF_REPO_KIND_MEDIA) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_AVAILABLE,
+ "Cannot update read-only repo");
+ return FALSE;
+ }
+
+ /* Just verify existence for local */
+ if (priv->kind == DNF_REPO_KIND_LOCAL) {
+ if (priv->last_check_error) {
+ if (error)
+ *error = g_error_copy(priv->last_check_error);
+ return FALSE;
+ }
+ /* If we didn't have an error in check, don't refresh
+ local repos */
+ return TRUE;
+ }
+
+ /* this needs to be set */
+ if (priv->location_tmp == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "location_tmp not set for %s",
+ priv->repo->getId().c_str());
+ return FALSE;
+ }
+
+ /* ensure we set the values from the keyfile */
+ if (!dnf_repo_set_keyfile_data(repo, TRUE, error))
+ return FALSE;
+
+ auto repoImpl = libdnf::repoGetImpl(priv->repo);
+
+ /* countme support */
+ repoImpl->addCountmeFlag(priv->repo_handle);
+
+ /* take lock */
+ ret = dnf_state_take_lock(state,
+ DNF_LOCK_TYPE_METADATA,
+ DNF_LOCK_MODE_PROCESS,
+ error);
+ if (!ret)
+ goto out;
+
+ /* set state */
+ ret = dnf_state_set_steps(state, error,
+ 95, /* download */
+ 5, /* check */
+ -1);
+ if (!ret)
+ goto out;
+
+ state_local = dnf_state_get_child(state);
+ dnf_state_action_start(state_local,
+ DNF_STATE_ACTION_DOWNLOAD_METADATA, NULL);
+
+ try {
+ if (repoImpl->isInSync()) {
+ /* reset timestamp */
+ ret = utimes(repoImpl->repomdFn.c_str(), NULL);
+ if (ret != 0)
+ g_debug("Failed to reset timestamp on repomd.xml");
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* skip check */
+ ret = dnf_state_finished(state, error);
+ goto out;
+ }
+ } catch (std::exception & ex) {
+ g_debug("Failed to verify if metadata is in sync: \"%s\". Proceding with download", ex.what());
+ }
+
+ /* remove the temporary space if it already exists */
+ if (g_file_test(priv->location_tmp, G_FILE_TEST_EXISTS)) {
+ ret = dnf_remove_recursive(priv->location_tmp, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* ensure exists */
+ rc = g_mkdir_with_parents(priv->location_tmp, 0755);
+ if (rc != 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG,
+ "Failed to create %s", priv->location_tmp);
+ goto out;
+ }
+
+ {
+ const auto & gpgkeys = priv->repo->getConfig()->gpgkey().getValue();
+ if (!gpgkeys.empty() &&
+ (priv->repo->getConfig()->repo_gpgcheck().getValue() || priv->repo->getConfig()->gpgcheck().getValue())) {
+ for (const auto & key : gpgkeys) {
+ const char *gpgkey = key.c_str();
+ g_autofree char *gpgkey_name = g_path_get_basename(gpgkey);
+ g_autofree char *key_tmp = g_build_filename(priv->location_tmp, gpgkey_name, NULL);
+
+ /* download and import public key */
+ if ((g_str_has_prefix(gpgkey, "https://") ||
+ g_str_has_prefix(gpgkey, "file://"))) {
+ g_debug("importing public key %s", gpgkey);
+
+ ret = dnf_repo_download_import_public_key(repo, gpgkey, key_tmp, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* do we autoimport this into librpm? */
+ if ((flags & DNF_REPO_UPDATE_FLAG_IMPORT_PUBKEY) > 0) {
+ ret = dnf_repo_add_public_key(repo, key_tmp, error);
+ if (!ret)
+ goto out;
+ }
+ }
+ }
+ }
+
+ g_debug("Attempting to update %s", priv->repo->getId().c_str());
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_LOCAL, 0L);
+ if (!ret)
+ goto out;
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_DESTDIR, priv->location_tmp);
+ if (!ret)
+ goto out;
+
+ /* Callback to display progress of downloading */
+ updatedata.state = state_local;
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_PROGRESSDATA, &updatedata);
+ if (!ret)
+ goto out;
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_PROGRESSCB, dnf_repo_update_state_cb);
+ if (!ret)
+ goto out;
+ /* Note this uses the same user data as PROGRESSDATA */
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_HMFCB, repo_mirrorlist_failure_cb);
+ if (!ret)
+ goto out;
+
+ /* see dnf_repo_check_internal */
+ if (!dnf_context_get_enable_filelists(priv->context)) {
+ const gchar *excluded_metadata_types[] = { "filelists", NULL };
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_YUMBLIST, excluded_metadata_types);
+ if (!ret)
+ goto out;
+ }
+
+ lr_result_clear(priv->repo_result);
+ ret = lr_handle_perform(priv->repo_handle,
+ priv->repo_result,
+ &error_local);
+ if (!ret) {
+ if (updatedata.last_mirror_failure_message) {
+ g_autofree gchar *orig_message = error_local->message;
+ error_local->message = g_strconcat(orig_message, "; Last error: ", updatedata.last_mirror_failure_message, NULL);
+ }
+
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_FETCH_SOURCE,
+ "cannot update repo '%s': %s",
+ dnf_repo_get_id(repo),
+ error_local->message);
+ goto out;
+ }
+
+ /* check the newer metadata is newer */
+ ret = lr_result_getinfo(priv->repo_result, &error_local,
+ LRR_YUM_TIMESTAMP, ×tamp_new);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to get timestamp: %s",
+ error_local->message);
+ goto out;
+ }
+ if ((flags & DNF_REPO_UPDATE_FLAG_FORCE) == 0 &&
+ timestamp_new < priv->timestamp_generated) {
+ g_debug("fresh metadata was older than what we have, ignoring");
+ if (!dnf_state_finished(state, error))
+ return FALSE;
+ goto out;
+ }
+
+ /* only simulate */
+ if (flags & DNF_REPO_UPDATE_FLAG_SIMULATE) {
+ g_debug("simulating, so not switching to new metadata");
+ ret = dnf_remove_recursive(priv->location_tmp, error);
+ goto out;
+ }
+
+ /* move the packages directory from the old cache to the new cache */
+ if (g_file_test(priv->packages, G_FILE_TEST_EXISTS)) {
+ ret = dnf_move_recursive(priv->packages, priv->packages_tmp, &error_local);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_FETCH_SOURCE,
+ "cannot move %s to %s: %s",
+ priv->packages, priv->packages_tmp, error_local->message);
+ goto out;
+ }
+ }
+
+ /* delete old /var/cache/PackageKit/metadata/$REPO/ */
+ ret = dnf_repo_clean(repo, error);
+ if (!ret)
+ goto out;
+
+ /* rename .tmp actual name */
+ ret = dnf_move_recursive(priv->location_tmp, priv->location, &error_local);
+ if (!ret) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_FETCH_SOURCE,
+ "cannot move %s to %s: %s",
+ priv->location_tmp, priv->location, error_local->message);
+ goto out;
+ }
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_DESTDIR, priv->location);
+ if (!ret)
+ goto out;
+ ret = lr_handle_setopt(priv->repo_handle, error,
+ LRO_GNUPGHOMEDIR, priv->keyring);
+ if (!ret)
+ goto out;
+
+ /* done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* now setup internal hawkey stuff */
+ state_local = dnf_state_get_child(state);
+ ret = dnf_repo_check(repo, G_MAXUINT, state_local, error);
+ if (!ret)
+ goto out;
+
+ /* signal that the vendor platform data is not resyned */
+ dnf_context_invalidate_full(priv->context, "updated repo cache",
+ DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT);
+
+ /* done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+out:
+ if (!ret) {
+ /* remove the .tmp dir on failure */
+ g_autoptr(GError) error_remove = NULL;
+ if (!dnf_remove_recursive(priv->location_tmp, &error_remove))
+ g_debug("Failed to remove %s: %s", priv->location_tmp, error_remove->message);
+ }
+ g_free(updatedata.last_mirror_failure_message);
+ g_free(updatedata.last_mirror_url);
+ dnf_state_release_locks(state);
+ if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL))
+ g_debug("Failed to reset LRO_PROGRESSCB to NULL");
+ if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_HMFCB, NULL))
+ g_debug("Failed to reset LRO_HMFCB to NULL");
+ if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef))
+ g_debug("Failed to set LRO_PROGRESSDATA to 0xdeadbeef");
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_repo_set_data:
+ * @repo: a #DnfRepo instance.
+ * @parameter: the UTF8 key.
+ * @value: the UTF8 value.
+ * @error: A #GError or %NULL
+ *
+ * Sets data on the repo.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_repo_set_data(DnfRepo *repo,
+ const gchar *parameter,
+ const gchar *value,
+ GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_key_file_set_string(priv->keyfile, priv->repo->getId().c_str(), parameter, value);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_repo_commit:
+ * @repo: a #DnfRepo instance.
+ * @error: A #GError or %NULL
+ *
+ * Commits data on the repo, which involves saving a new .repo file.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.4
+ **/
+gboolean
+dnf_repo_commit(DnfRepo *repo, GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ g_autofree gchar *data = NULL;
+
+ /* cannot change DVD contents */
+ if (priv->kind == DNF_REPO_KIND_MEDIA) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG,
+ "Cannot commit to read-only media");
+ return FALSE;
+ }
+
+ /* dump updated file to disk */
+ data = g_key_file_to_data(priv->keyfile, NULL, error);
+ if (data == NULL)
+ return FALSE;
+ return g_file_set_contents(priv->filename, data, -1, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_repo_checksum_hy_to_lr:
+ **/
+static LrChecksumType
+dnf_repo_checksum_hy_to_lr(int checksum_hy)
+{
+ if (checksum_hy == G_CHECKSUM_MD5)
+ return LR_CHECKSUM_MD5;
+ if (checksum_hy == G_CHECKSUM_SHA1)
+ return LR_CHECKSUM_SHA1;
+ if (checksum_hy == G_CHECKSUM_SHA256)
+ return LR_CHECKSUM_SHA256;
+ return LR_CHECKSUM_UNKNOWN;
+}
+
+typedef struct
+{
+ gchar *last_mirror_url;
+ gchar *last_mirror_failure_message;
+ guint64 downloaded;
+ guint64 download_size;
+} GlobalDownloadData;
+
+typedef struct
+{
+ DnfPackage *pkg;
+ DnfState *state;
+ guint64 downloaded;
+ GlobalDownloadData *global_download_data;
+} PackageDownloadData;
+
+static int
+package_download_update_state_cb(void *user_data,
+ gdouble total_to_download,
+ gdouble now_downloaded)
+{
+ auto data = static_cast<PackageDownloadData *>(user_data);
+ GlobalDownloadData *global_data = data->global_download_data;
+ gboolean ret;
+ gdouble percentage;
+ guint64 previously_downloaded;
+
+ /* abort */
+ if (!dnf_state_check(data->state, NULL))
+ return -1;
+
+ /* nothing sensible */
+ if (total_to_download < 0 || now_downloaded < 0)
+ return 0;
+
+ dnf_state_action_start(data->state,
+ DNF_STATE_ACTION_DOWNLOAD_PACKAGES,
+ dnf_package_get_package_id(data->pkg));
+
+ previously_downloaded = data->downloaded;
+ data->downloaded = now_downloaded;
+
+ global_data->downloaded += (now_downloaded - previously_downloaded);
+
+ /* set percentage */
+ percentage = 100.0f * global_data->downloaded / global_data->download_size;
+ ret = dnf_state_set_percentage(data->state, percentage);
+ if (ret) {
+ g_debug("update state %d/%d",
+ (int)global_data->downloaded,
+ (int)global_data->download_size);
+ }
+
+ return 0;
+}
+
+static int
+package_download_end_cb(void *user_data,
+ LrTransferStatus status,
+ const char *msg)
+{
+ auto data = static_cast<PackageDownloadData *>(user_data);
+
+ g_slice_free(PackageDownloadData, data);
+
+ return LR_CB_OK;
+}
+
+static int
+mirrorlist_failure_cb(void *user_data,
+ const char *message,
+ const char *url)
+{
+ auto data = static_cast<PackageDownloadData *>(user_data);
+ auto global_data = data->global_download_data;
+
+ if (global_data->last_mirror_url)
+ goto out;
+
+ global_data->last_mirror_url = g_strdup(url);
+ global_data->last_mirror_failure_message = g_strdup(message);
+out:
+ return LR_CB_OK;
+}
+
+LrHandle *
+dnf_repo_get_lr_handle(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE (repo);
+ return priv->repo_handle;
+}
+
+LrResult *
+dnf_repo_get_lr_result(DnfRepo *repo)
+{
+ DnfRepoPrivate *priv = GET_PRIVATE (repo);
+ return priv->repo_result;
+}
+
+/**
+ * dnf_repo_download_package:
+ * @repo: a #DnfRepo instance.
+ * @pkg: a #DnfPackage *instance.
+ * @directory: the destination directory.
+ * @state: a #DnfState.
+ * @error: a #GError or %NULL..
+ *
+ * Downloads a package from a repo.
+ *
+ * Returns: the complete filename of the downloaded file
+ *
+ * Since: 0.1.0
+ **/
+gchar *
+dnf_repo_download_package(DnfRepo *repo,
+ DnfPackage *pkg,
+ const gchar *directory,
+ DnfState *state,
+ GError **error) try
+{
+ g_autoptr(GPtrArray) packages = g_ptr_array_new();
+ g_autofree gchar *basename = NULL;
+
+ g_ptr_array_add(packages, pkg);
+
+ if (!dnf_repo_download_packages(repo, packages, directory, state, error))
+ return NULL;
+
+ /* build return value */
+ basename = g_path_get_basename(dnf_package_get_location(pkg));
+ return g_build_filename(directory, basename, NULL);
+} CATCH_TO_GERROR(NULL)
+
+/**
+ * dnf_repo_download_packages:
+ * @repo: a #DnfRepo instance.
+ * @packages: (element-type DnfPackage): an array of packages, must be from this repo
+ * @directory: the destination directory.
+ * @state: a #DnfState.
+ * @error: a #GError or %NULL.
+ *
+ * Downloads multiple packages from a repo. The target filename will be
+ * equivalent to `g_path_get_basename (dnf_package_get_location (pkg))`.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.2.3
+ **/
+gboolean
+dnf_repo_download_packages(DnfRepo *repo,
+ GPtrArray *packages,
+ const gchar *directory,
+ DnfState *state,
+ GError **error) try
+{
+ DnfRepoPrivate *priv = GET_PRIVATE(repo);
+ gboolean ret = FALSE;
+ guint i;
+ GSList *package_targets = NULL;
+ GlobalDownloadData global_data = { 0, };
+ g_autoptr(GError) error_local = NULL;
+ g_autofree gchar *directory_slash = NULL;
+
+ /* ensure we reset the values from the keyfile */
+ if (!dnf_repo_set_keyfile_data(repo, TRUE, error))
+ goto out;
+
+ /* if nothing specified then use cachedir */
+ if (directory == NULL) {
+ directory_slash = g_build_filename(priv->packages, "/", NULL);
+ if (!g_file_test(directory_slash, G_FILE_TEST_EXISTS)) {
+ if (g_mkdir_with_parents(directory_slash, 0755) != 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "Failed to create %s",
+ directory_slash);
+ goto out;
+ }
+ }
+ } else {
+ /* librepo uses the GNU basename() function to find out if the
+ * output directory is fully specified as a filename, but
+ * basename needs a trailing '/' to detect it's not a filename */
+ directory_slash = g_build_filename(directory, "/", NULL);
+ }
+
+ global_data.download_size = dnf_package_array_get_download_size(packages);
+ for (i = 0; i < packages->len; i++) {
+ auto pkg = static_cast<DnfPackage *>(packages->pdata[i]);
+ PackageDownloadData *data;
+ LrPackageTarget *target;
+ const unsigned char *checksum;
+ int checksum_type;
+ g_autofree char *checksum_str = NULL;
+
+ g_debug("downloading %s to %s",
+ dnf_package_get_location(pkg),
+ directory_slash);
+
+ data = g_slice_new0(PackageDownloadData);
+ data->pkg = pkg;
+ data->state = state;
+ data->global_download_data = &global_data;
+
+ checksum = dnf_package_get_chksum(pkg, &checksum_type);
+ checksum_str = hy_chksum_str(checksum, checksum_type);
+
+ std::string encodedUrl = dnf_package_get_location(pkg);
+ if (encodedUrl.find("://") == std::string::npos) {
+ encodedUrl = libdnf::urlEncode(encodedUrl, "/");
+ }
+
+ target = lr_packagetarget_new_v2(priv->repo_handle,
+ encodedUrl.c_str(),
+ directory_slash,
+ dnf_repo_checksum_hy_to_lr(checksum_type),
+ checksum_str,
+ dnf_package_get_downloadsize(pkg),
+ dnf_package_get_baseurl(pkg),
+ TRUE,
+ package_download_update_state_cb,
+ data,
+ package_download_end_cb,
+ mirrorlist_failure_cb,
+ error);
+ if (target == NULL)
+ goto out;
+
+ package_targets = g_slist_prepend(package_targets, target);
+ }
+
+ ret = lr_download_packages(package_targets, LR_PACKAGEDOWNLOAD_FAILFAST, &error_local);
+ if (!ret) {
+ if (g_error_matches(error_local,
+ LR_PACKAGE_DOWNLOADER_ERROR,
+ LRE_ALREADYDOWNLOADED)) {
+ /* ignore */
+ g_clear_error(&error_local);
+ } else {
+ if (global_data.last_mirror_failure_message) {
+ g_autofree gchar *orig_message = error_local->message;
+ error_local->message = g_strconcat(orig_message, "; Last error: ", global_data.last_mirror_failure_message, NULL);
+ }
+ g_propagate_error(error, error_local);
+ error_local = NULL;
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+out:
+ if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSCB, NULL))
+ g_debug("Failed to reset LRO_PROGRESSCB to NULL");
+ if (!lr_handle_setopt(priv->repo_handle, NULL, LRO_PROGRESSDATA, 0xdeadbeef))
+ g_debug("Failed to set LRO_PROGRESSDATA to 0xdeadbeef");
+ g_free(global_data.last_mirror_failure_message);
+ g_free(global_data.last_mirror_url);
+ g_slist_free_full(package_targets, (GDestroyNotify)lr_packagetarget_free);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_repo_new:
+ * @context: A #DnfContext instance
+ *
+ * Creates a new #DnfRepo.
+ *
+ * Returns:(transfer full): a #DnfRepo
+ *
+ * Since: 0.1.0
+ **/
+DnfRepo *
+dnf_repo_new(DnfContext *context)
+{
+ auto repo = DNF_REPO(g_object_new(DNF_TYPE_REPO, NULL));
+ auto priv = GET_PRIVATE(repo);
+ priv->context = context;
+ g_object_add_weak_pointer(G_OBJECT(priv->context),(void **) &priv->context);
+ return repo;
+}
+
+HyRepo dnf_repo_get_hy_repo(DnfRepo *repo)
+{
+ auto priv = GET_PRIVATE(repo);
+ return priv->repo;
+}
+
+/**
+ * dnf_repo_add_metadata_type_to_download:
+ * @repo: a #DnfRepo instance.
+ * @metadataType: a #gchar, e.g. %"filelist"
+ *
+ * Ask for additional repository metadata type to download.
+ * Given metadata are appended to the default metadata set when repository is downloaded.
+ *
+ * Since: 0.24.0
+ **/
+void
+dnf_repo_add_metadata_type_to_download(DnfRepo * repo, const gchar * metadataType)
+{
+ auto priv = GET_PRIVATE(repo);
+ libdnf::repoGetImpl(priv->repo)->additionalMetadata.insert(metadataType);
+}
+
+/**
+ * dnf_repo_get_metadata_content:
+ * @repo: a #DnfRepo instance.
+ * @metadataType: a #gchar, e.g. %"filelist"
+ * @content: a #gpointer, a pointer to allocated memory with content of metadata file
+ * @length: a #gsize
+ * @error: a #GError or %NULL.
+ *
+ * Return content of the particular downloaded repository metadata.
+ * Content of compressed metadata file is returned uncompressed.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.24.0
+ **/
+gboolean
+dnf_repo_get_metadata_content(DnfRepo * repo, const gchar * metadataType, gpointer * content,
+ gsize * length, GError ** error) try
+{
+ auto path = dnf_repo_get_filename_md(repo, metadataType);
+ if (!path) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FILE_NOT_FOUND,
+ "Cannot found metadata type \"%s\" for repo \"%s\"",
+ metadataType, dnf_repo_get_id(repo));
+ return FALSE;
+ }
+
+ try {
+ auto mdfile = libdnf::File::newFile(path);
+ mdfile->open("r");
+ const auto &fcontent = mdfile->getContent();
+ mdfile->close();
+ auto data = g_malloc(fcontent.length());
+ memcpy(data, fcontent.data(), fcontent.length());
+ *content = data;
+ *length = fcontent.length();
+ return TRUE;
+ } catch (std::runtime_error & ex) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_FAILED,
+ "Cannot load metadata type \"%s\" for repo \"%s\": %s",
+ metadataType, dnf_repo_get_id(repo), ex.what());
+ return FALSE;
+ }
+} CATCH_TO_GERROR(FALSE)
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_REPO_H
+#define __DNF_REPO_H
+
+#include <glib-object.h>
+
+#include "hy-repo.h"
+#include "hy-package.h"
+
+#include "dnf-context.h"
+#include "dnf-state.h"
+
+#include <librepo/librepo.h>
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_REPO (dnf_repo_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfRepo, dnf_repo, DNF, REPO, GObject)
+
+struct _DnfRepoClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+/**
+ * DnfRepoUpdateFlags:
+ * @DNF_REPO_UPDATE_FLAG_NONE: No flags set
+ * @DNF_REPO_UPDATE_FLAG_FORCE: Force the repo to be updated
+ * @DNF_REPO_UPDATE_FLAG_IMPORT_PUBKEY: Import the repo public key to librpm if possible
+ * @DNF_REPO_UPDATE_FLAG_SIMULATE: Do not actually update the repo
+ *
+ * The update flags.
+ **/
+typedef enum {
+ DNF_REPO_UPDATE_FLAG_NONE = 0,
+ DNF_REPO_UPDATE_FLAG_FORCE = 1,
+ DNF_REPO_UPDATE_FLAG_IMPORT_PUBKEY = 2,
+ DNF_REPO_UPDATE_FLAG_SIMULATE = 4,
+ /*< private >*/
+ DNF_REPO_UPDATE_FLAG_LAST
+} DnfRepoUpdateFlags;
+
+/**
+ * DnfRepoKind:
+ * @DNF_REPO_KIND_REMOTE: A remote repo
+ * @DNF_REPO_KIND_MEDIA: A media repo, e.g. a DVD
+ * @DNF_REPO_KIND_LOCAL: A local repo, e.g. file://
+ *
+ * The repo kind.
+ **/
+typedef enum {
+ DNF_REPO_KIND_REMOTE,
+ DNF_REPO_KIND_MEDIA,
+ DNF_REPO_KIND_LOCAL,
+ /*< private >*/
+ DNF_REPO_KIND_LAST
+} DnfRepoKind;
+
+/**
+ * DnfRepoEnabled:
+ * @DNF_REPO_ENABLED_NONE: Source is disabled
+ * @DNF_REPO_ENABLED_PACKAGES: Source is fully enabled
+ * @DNF_REPO_ENABLED_METADATA: Only repo metadata is enabled
+ *
+ * How enabled is the repo.
+ **/
+typedef enum {
+ DNF_REPO_ENABLED_NONE = 0,
+ DNF_REPO_ENABLED_PACKAGES = 1,
+ DNF_REPO_ENABLED_METADATA = 2,
+ /*< private >*/
+ DNF_REPO_ENABLED_LAST
+} DnfRepoEnabled;
+
+DnfRepo *dnf_repo_new (DnfContext *context);
+
+/* getters */
+const gchar *dnf_repo_get_id (DnfRepo *repo);
+const gchar *dnf_repo_get_location (DnfRepo *repo);
+const gchar *dnf_repo_get_filename (DnfRepo *repo);
+const gchar *dnf_repo_get_packages (DnfRepo *repo);
+gchar ** dnf_repo_get_public_keys (DnfRepo *repo);
+DnfRepoEnabled dnf_repo_get_enabled (DnfRepo *repo);
+gboolean dnf_repo_get_required (DnfRepo *repo);
+guint dnf_repo_get_cost (DnfRepo *repo);
+gboolean dnf_repo_get_module_hotfixes (DnfRepo *repo);
+guint dnf_repo_get_metadata_expire (DnfRepo *repo);
+DnfRepoKind dnf_repo_get_kind (DnfRepo *repo);
+gchar **dnf_repo_get_exclude_packages (DnfRepo *repo);
+gboolean dnf_repo_get_gpgcheck (DnfRepo *repo);
+gboolean dnf_repo_get_gpgcheck_md (DnfRepo *repo);
+gchar *dnf_repo_get_description (DnfRepo *repo);
+guint64 dnf_repo_get_timestamp_generated(DnfRepo *repo);
+guint dnf_repo_get_n_solvables (DnfRepo *repo);
+const gchar *dnf_repo_get_filename_md (DnfRepo *repo,
+ const gchar *md_kind);
+#ifndef __GI_SCANNER__
+HyRepo dnf_repo_get_repo (DnfRepo *repo);
+#endif
+gboolean dnf_repo_is_devel (DnfRepo *repo);
+gboolean dnf_repo_is_local (DnfRepo *repo);
+gboolean dnf_repo_is_source (DnfRepo *repo);
+
+/* setters */
+void dnf_repo_set_id (DnfRepo *repo,
+ const gchar *id);
+void dnf_repo_set_location (DnfRepo *repo,
+ const gchar *location);
+void dnf_repo_set_location_tmp (DnfRepo *repo,
+ const gchar *location_tmp);
+void dnf_repo_set_filename (DnfRepo *repo,
+ const gchar *filename);
+void dnf_repo_set_packages (DnfRepo *repo,
+ const gchar *packages);
+void dnf_repo_set_packages_tmp (DnfRepo *repo,
+ const gchar *packages_tmp);
+void dnf_repo_set_enabled (DnfRepo *repo,
+ DnfRepoEnabled enabled);
+void dnf_repo_set_required (DnfRepo *repo,
+ gboolean required);
+void dnf_repo_set_cost (DnfRepo *repo,
+ guint cost);
+void dnf_repo_set_module_hotfixes (DnfRepo *repo,
+ gboolean module_hotfixes);
+void dnf_repo_set_kind (DnfRepo *repo,
+ DnfRepoKind kind);
+void dnf_repo_set_gpgcheck (DnfRepo *repo,
+ gboolean gpgcheck_pkgs);
+void dnf_repo_set_skip_if_unavailable(DnfRepo *repo,
+ gboolean skip_if_unavailable);
+void dnf_repo_set_gpgcheck_md (DnfRepo *repo,
+ gboolean gpgcheck_md);
+void dnf_repo_set_keyfile (DnfRepo *repo,
+ GKeyFile *keyfile);
+void dnf_repo_set_metadata_expire (DnfRepo *repo,
+ guint metadata_expire);
+gboolean dnf_repo_setup (DnfRepo *repo,
+ GError **error);
+
+/* object methods */
+gboolean dnf_repo_check (DnfRepo *repo,
+ guint permissible_cache_age,
+ DnfState *state,
+ GError **error);
+gboolean dnf_repo_update (DnfRepo *repo,
+ DnfRepoUpdateFlags flags,
+ DnfState *state,
+ GError **error);
+gboolean dnf_repo_clean (DnfRepo *repo,
+ GError **error);
+gboolean dnf_repo_set_data (DnfRepo *repo,
+ const gchar *parameter,
+ const gchar *value,
+ GError **error);
+gboolean dnf_repo_commit (DnfRepo *repo,
+ GError **error);
+
+#ifndef __GI_SCANNER__
+LrHandle * dnf_repo_get_lr_handle (DnfRepo *repo);
+
+LrResult * dnf_repo_get_lr_result (DnfRepo *repo);
+#endif
+
+#ifndef __GI_SCANNER__
+gchar *dnf_repo_download_package (DnfRepo *repo,
+ DnfPackage * pkg,
+ const gchar *directory,
+ DnfState *state,
+ GError **error);
+gboolean dnf_repo_download_packages (DnfRepo *repo,
+ GPtrArray *pkgs,
+ const gchar *directory,
+ DnfState *state,
+ GError **error);
+
+HyRepo dnf_repo_get_hy_repo(DnfRepo *repo);
+#endif
+
+void dnf_repo_add_metadata_type_to_download (DnfRepo *repo,
+ const gchar *metadataType);
+gboolean dnf_repo_get_metadata_content (DnfRepo *repo,
+ const gchar *metadataType,
+ gpointer *content,
+ gsize *length,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_REPO_H */
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_REPO_HPP
+#define __DNF_REPO_HPP
+
+#include "dnf-repo.h"
+
+inline DnfRepoEnabled operator|(DnfRepoEnabled a, DnfRepoEnabled b)
+{
+ return static_cast<DnfRepoEnabled>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline DnfRepoEnabled & operator|=(DnfRepoEnabled & a, DnfRepoEnabled b)
+{
+ return a = a | b;
+}
+
+
+#endif /* __DNF_REPO_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_RPMTS_PRIVATE_HPP
+#define __DNF_RPMTS_PRIVATE_HPP
+
+#include "dnf-rpmts.h"
+
+
+gboolean dnf_rpmts_add_install_filename2(rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ gboolean is_update,
+ DnfPackage *pkg,
+ GError **error);
+
+gboolean dnf_rpmts_add_reinstall_filename(rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ GError **error);
+
+
+#endif /* __DNF_RPMTS_PRIVATE_HPP */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * Most of this code was taken from Zif, libzif/zif-transaction.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-goal
+ * @short_description: Helper methods for dealing with rpm transactions.
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * These methods make it easier to deal with rpm transactions.
+ */
+
+
+#include <glib.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmdb.h>
+
+#include "catch-error.hpp"
+#include "sack/packageset.hpp"
+#include "hy-package-private.hpp"
+#include "dnf-rpmts-private.hpp"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+
+#include "utils/bgettext/bgettext-lib.h"
+#include "dnf-package.h"
+
+// older RPM doesn't have RPMTAG_MODULARITYLABEL defined
+#ifndef RPMTAG_MODULARITYLABEL
+#define RPMTAG_MODULARITYLABEL 5096
+#endif
+
+
+static gboolean
+test_fail_safe(Header * hdr, DnfPackage * pkg, GError **error)
+{
+ if (dnf_package_installed(pkg)) {
+ return TRUE;
+ }
+ if (strcmp(dnf_package_get_reponame(pkg), HY_CMDLINE_REPO_NAME) == 0) {
+ return TRUE;
+ }
+ if (auto repo = dnf_package_get_repo(pkg)) {
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ rpmtd td = rpmtdNew();
+ gboolean ret = TRUE;
+ if (headerGet(*hdr, RPMTAG_MODULARITYLABEL, td, HEADERGET_MINMEM)) {
+ if (rpmtdGetString(td)) {
+ DnfSack * sack = dnf_package_get_sack(pkg);
+ std::unique_ptr<libdnf::PackageSet> includes(dnf_sack_get_module_includes(sack));
+ if (!includes || !includes->has(dnf_package_get_id(pkg))) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("No available modular metadata for modular package '%s'; "
+ "cannot be installed on the system"),
+ dnf_package_get_nevra(pkg));
+ ret = FALSE;
+ }
+ }
+ }
+ rpmtdFreeData(td);
+ rpmtdFree(td);
+ return ret;
+}
+
+static gboolean
+result_is_accepted(gint result, gboolean allow_untrusted, const gchar *filename, GError **error) {
+ /* be less strict when we're allowing untrusted transactions */
+ if (allow_untrusted) {
+ switch(result) {
+ case RPMRC_NOKEY:
+ case RPMRC_NOTFOUND:
+ case RPMRC_NOTTRUSTED:
+ case RPMRC_OK:
+ return TRUE;
+ case RPMRC_FAIL:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("signature does not verify for %s"),
+ filename);
+ return FALSE;
+ default:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to open(generic error): %s"),
+ filename);
+ return FALSE;
+ }
+ } else {
+ switch(result) {
+ case RPMRC_OK:
+ return TRUE;
+ case RPMRC_NOTTRUSTED:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to verify key for %s"),
+ filename);
+ return FALSE;
+ case RPMRC_NOKEY:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("public key unavailable for %s"),
+ filename);
+ return FALSE;
+ case RPMRC_NOTFOUND:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("signature not found for %s"),
+ filename);
+ return FALSE;
+ case RPMRC_FAIL:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("signature does not verify for %s"),
+ filename);
+ return FALSE;
+ default:
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to open(generic error): %s"),
+ filename);
+ return FALSE;
+ }
+ }
+}
+
+gboolean
+dnf_rpmts_add_reinstall_filename(rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ GError **error) try
+{
+ gboolean ret = TRUE;
+ gint res;
+ Header hdr;
+ FD_t fd;
+
+ /* open this */
+ fd = Fopen(filename, "r.ufdio");
+ res = rpmReadPackageFile(ts, fd, filename, &hdr);
+
+ if (!result_is_accepted(res, allow_untrusted, filename, error)) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* add to the transaction */
+ res = rpmtsAddReinstallElement(ts, hdr, (fnpyKey) filename);
+ if (res != 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to add reinstall element: %1$s [%2$i]"),
+ filename, res);
+ goto out;
+ }
+out:
+ Fclose(fd);
+ headerFree(hdr);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_rpmts_add_install_filename2(rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ gboolean is_update,
+ DnfPackage * pkg,
+ GError **error) try
+{
+ gboolean ret = TRUE;
+ gint res;
+ Header hdr;
+ FD_t fd;
+
+ /* open this */
+ fd = Fopen(filename, "r.ufdio");
+ res = rpmReadPackageFile(ts, fd, filename, &hdr);
+
+ if (!result_is_accepted(res, allow_untrusted, filename, error)) {
+ ret = FALSE;
+ goto out;
+ }
+ if (pkg) {
+ if (!test_fail_safe(&hdr, pkg, error)) {
+ ret = FALSE;
+ goto out;
+ }
+ }
+
+ /* add to the transaction */
+ res = rpmtsAddInstallElement(ts, hdr, (fnpyKey) filename, is_update, NULL);
+ if (res != 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to add install element: %1$s [%2$i]"),
+ filename, res);
+ goto out;
+ }
+out:
+ Fclose(fd);
+ headerFree(hdr);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_rpmts_add_install_filename:
+ * @ts: a #rpmts instance.
+ * @filename: the package.
+ * @allow_untrusted: is we can add untrusted packages.
+ * @is_update: if the package is an update.
+ * @error: a #GError or %NULL..
+ *
+ * Add to the transaction a package to be installed.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_rpmts_add_install_filename(rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ gboolean is_update,
+ GError **error) try
+{
+ return dnf_rpmts_add_install_filename2(ts, filename, allow_untrusted, is_update, NULL, error);
+} CATCH_TO_GERROR(FALSE)
+
+
+/**
+ * dnf_rpmts_look_for_problems:
+ * @ts: a #rpmts instance.
+ * @error: a #GError or %NULL..
+ *
+ * Look for problems in the transaction.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_rpmts_look_for_problems(rpmts ts, GError **error) try
+{
+ gboolean ret = TRUE;
+ rpmProblem prob;
+ rpmpsi psi;
+ rpmps probs = NULL;
+ g_autoptr(GString) string = NULL;
+
+ /* get a list of problems */
+ probs = rpmtsProblems(ts);
+ if (rpmpsNumProblems(probs) == 0)
+ goto out;
+
+ /* parse problems */
+ string = g_string_new("");
+ psi = rpmpsInitIterator(probs);
+ while (rpmpsNextIterator(psi) >= 0) {
+ g_autofree gchar *msg = NULL;
+ prob = rpmpsGetProblem(psi);
+ msg = rpmProblemString(prob);
+ g_string_append(string, msg);
+ g_string_append(string, "\n");
+ }
+ rpmpsFreeIterator(psi);
+
+ /* set error */
+ ret = FALSE;
+
+ /* we failed, and got a reason to report */
+ if (string->len > 0) {
+ g_string_set_size(string, string->len - 1);
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Error running transaction: %s"),
+ string->str);
+ goto out;
+ }
+
+ /* we failed, and got no reason why */
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Error running transaction and no problems were reported!"));
+out:
+ rpmpsFree(probs);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_rpmts_log_handler_cb:
+ **/
+static int
+dnf_rpmts_log_handler_cb(rpmlogRec rec, rpmlogCallbackData data)
+{
+ GString **string =(GString **) data;
+
+ /* only log errors */
+ if (rpmlogRecPriority(rec) != RPMLOG_ERR)
+ return RPMLOG_DEFAULT;
+
+ /* do not log internal BDB errors */
+ if (g_strstr_len(rpmlogRecMessage(rec), -1, "BDB") != NULL)
+ return 0;
+
+ /* create string if required */
+ if (*string == NULL)
+ *string = g_string_new("");
+
+ /* if text already exists, join them */
+ if ((*string)->len > 0)
+ g_string_append(*string, ": ");
+ g_string_append(*string, rpmlogRecMessage(rec));
+
+ /* remove the trailing /n which rpm does */
+ if ((*string)->len > 0)
+ g_string_truncate(*string,(*string)->len - 1);
+ return 0;
+}
+
+/**
+ * dnf_rpmts_find_package:
+ **/
+static Header
+dnf_rpmts_find_package(rpmts ts, DnfPackage *pkg, GError **error)
+{
+ Header hdr = NULL;
+ rpmdbMatchIterator iter;
+ unsigned int recOffset;
+ g_autoptr(GString) rpm_error = NULL;
+
+ /* find package by db-id */
+ recOffset = dnf_package_get_rpmdbid(pkg);
+ rpmlogSetCallback(dnf_rpmts_log_handler_cb, &rpm_error);
+ iter = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
+ &recOffset, sizeof(recOffset));
+ if (iter == NULL) {
+ if (rpm_error != NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_UNFINISHED_TRANSACTION,
+ rpm_error->str);
+ } else {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_UNFINISHED_TRANSACTION,
+ _("Fatal error, run database recovery"));
+ }
+ goto out;
+ }
+ hdr = rpmdbNextIterator(iter);
+ if (hdr == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_NOT_FOUND,
+ _("failed to find package %s"),
+ dnf_package_get_name(pkg));
+ goto out;
+ }
+
+ /* success */
+ headerLink(hdr);
+out:
+ rpmlogSetCallback(NULL, NULL);
+ if (iter != NULL)
+ rpmdbFreeIterator(iter);
+ return hdr;
+}
+
+/**
+ * dnf_rpmts_add_remove_pkg:
+ * @ts: a #rpmts instance.
+ * @pkg: a #DnfPackage *instance.
+ * @error: a #GError or %NULL..
+ *
+ * Adds to the transaction a package to be removed.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_rpmts_add_remove_pkg(rpmts ts, DnfPackage *pkg, GError **error) try
+{
+ gboolean ret = TRUE;
+ gint retval;
+ Header hdr;
+
+ hdr = dnf_rpmts_find_package(ts, pkg, error);
+ if (hdr == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* remove it */
+ retval = rpmtsAddEraseElement(ts, hdr, -1);
+ if (retval != 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("could not add erase element %1$s(%2$i)"),
+ dnf_package_get_name(pkg), retval);
+ goto out;
+ }
+out:
+ if (hdr != NULL)
+ headerFree(hdr);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_RPMTS_H
+#define __DNF_RPMTS_H
+
+#include <glib.h>
+#include <rpm/rpmts.h>
+#include "hy-package.h"
+
+G_BEGIN_DECLS
+
+gboolean dnf_rpmts_add_install_filename (rpmts ts,
+ const gchar *filename,
+ gboolean allow_untrusted,
+ gboolean is_update,
+ GError **error);
+gboolean dnf_rpmts_add_remove_pkg (rpmts ts,
+ DnfPackage * pkg,
+ GError **error);
+gboolean dnf_rpmts_look_for_problems (rpmts ts,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_RPMTS_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2015 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_SACK_INTERNAL_H
+#define HY_SACK_INTERNAL_H
+
+#include <stdio.h>
+#include <solv/pool.h>
+#include <vector>
+
+#include "dnf-sack.h"
+#include "hy-query.h"
+#include "sack/packageset.hpp"
+#include "sack/query.hpp"
+#include "module/ModulePackage.hpp"
+#include "module/ModulePackageContainer.hpp"
+
+typedef Id (*dnf_sack_running_kernel_fn_t) (DnfSack *sack);
+
+/**
+ * @brief Store Map with only pkg_solvables to increase query performance
+ *
+ * @param sack p_sack:...
+ * @param pkg_solvables Map with only all pkg_solvables
+ * @param pool_nsolvables Number of pool_nsolvables in pool. It used as checksum.
+ */
+void dnf_sack_set_pkg_solvables(DnfSack *sack, Map *pkg_solvables, int pool_nsolvables);
+
+/**
+ * @brief Returns number of pool_nsolvables at time of creation of pkg_solvables. It can be used to
+ * verify Map contant
+ *
+ * @param sack p_sack:...
+ * @return int
+ */
+int dnf_sack_get_pool_nsolvables(DnfSack *sack);
+
+/**
+ * @brief Returns pointer PackageSet with every package solvable in pool
+ *
+ * @param sack p_sack:...
+ * @return Map*
+ */
+libdnf::PackageSet *dnf_sack_get_pkg_solvables(DnfSack *sack);
+libdnf::ModulePackageContainer * dnf_sack_set_module_container(
+ DnfSack *sack, libdnf::ModulePackageContainer * newConteiner);
+libdnf::ModulePackageContainer * dnf_sack_get_module_container(DnfSack *sack);
+void dnf_sack_make_provides_ready (DnfSack *sack);
+Id dnf_sack_running_kernel (DnfSack *sack);
+void dnf_sack_recompute_considered_map (DnfSack * sack, Map ** considered, libdnf::Query::ExcludeFlags flags);
+void dnf_sack_recompute_considered (DnfSack *sack);
+Id dnf_sack_last_solvable (DnfSack *sack);
+const char * dnf_sack_get_arch (DnfSack *sack);
+void dnf_sack_set_provides_not_ready(DnfSack *sack);
+void dnf_sack_set_considered_to_update(DnfSack * sack);
+Queue *dnf_sack_get_installonly (DnfSack *sack);
+void dnf_sack_set_running_kernel_fn (DnfSack *sack,
+ dnf_sack_running_kernel_fn_t fn);
+DnfPackage *dnf_sack_add_cmdline_package_flags (DnfSack *sack,
+ const char *fn, const int flags);
+std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer::ModuleErrorType> dnf_sack_filter_modules_v2(
+ DnfSack *sack, libdnf::ModulePackageContainer * moduleContainer, const char ** hotfixRepos,
+ const char *install_root, const char * platformModule, bool updateOnly, bool debugSolver, bool applyObsoletes);
+
+std::vector<libdnf::ModulePackage *> requiresModuleEnablement(DnfSack * sack, const libdnf::PackageSet * installSet);
+
+#endif // HY_SACK_INTERNAL_H
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2015 Red Hat, Inc.
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-sack
+ * @short_description: A package sack
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * Sacks are repositories of packages.
+ *
+ * See also: #DnfContext
+ */
+
+
+#include <algorithm>
+#include <assert.h>
+#include <errno.h>
+#include <functional>
+#include <unistd.h>
+#include <iostream>
+#include <list>
+#include <set>
+
+extern "C" {
+#include <solv/evr.h>
+#include <solv/pool.h>
+#include <solv/poolarch.h>
+#include <solv/repo.h>
+#include <solv/repo_deltainfoxml.h>
+#include <solv/repo_repomdxml.h>
+#include <solv/repo_updateinfoxml.h>
+#include <solv/repo_rpmmd.h>
+#include <solv/repo_rpmdb.h>
+#include <solv/repo_solv.h>
+#include <solv/repo_write.h>
+#include <solv/solv_xfopen.h>
+#include <solv/solver.h>
+}
+
+#include <cstring>
+#include <sstream>
+
+#include "catch-error.hpp"
+#include "dnf-context.hpp"
+#include "dnf-types.h"
+#include "dnf-package.h"
+#include "hy-iutil-private.hpp"
+#include "hy-query.h"
+#include "hy-repo-private.hpp"
+#include "dnf-sack-private.hpp"
+#include "hy-util.h"
+
+#include "utils/bgettext/bgettext-lib.h"
+
+#include "sack/query.hpp"
+#include "nevra.hpp"
+#include "conf/ConfigParser.hpp"
+#include "conf/OptionBool.hpp"
+#include "module/ModulePackageContainer.hpp"
+#include "module/ModulePackage.hpp"
+#include "repo/Repo-private.hpp"
+#include "repo/solvable/DependencyContainer.hpp"
+#include "utils/File.hpp"
+#include "utils/utils.hpp"
+#include "log.hpp"
+#include "tinyformat/tinyformat.hpp"
+
+
+#define DEFAULT_CACHE_ROOT "/var/cache/hawkey"
+#define DEFAULT_CACHE_USER "/var/tmp/hawkey"
+
+typedef struct
+{
+ Id running_kernel_id;
+ Map *pkg_excludes;
+ Map *pkg_includes;
+ Map *repo_excludes;
+ Map *module_excludes;
+ Map *module_includes; /* To fast identify enabled modular packages */
+ Map *pkg_solvables; /* Map representing only solvable pkgs of query */
+ int pool_nsolvables; /* Number of nsolvables for creation of pkg_solvables*/
+ Pool *pool;
+ Queue installonly;
+ Repo *cmdline_repo;
+ gboolean considered_uptodate;
+ gboolean have_set_arch;
+ gboolean all_arch;
+ gboolean provides_ready;
+ gboolean allow_vendor_change;
+ gchar *cache_dir;
+ char *arch;
+ dnf_sack_running_kernel_fn_t running_kernel_fn;
+ guint installonly_limit;
+ libdnf::ModulePackageContainer * moduleContainer;
+} DnfSackPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfSack, dnf_sack, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfSackPrivate *>(dnf_sack_get_instance_private (o)))
+
+
+/**
+ * dnf_sack_finalize:
+ **/
+static void
+dnf_sack_finalize(GObject *object)
+{
+ DnfSack *sack = DNF_SACK(object);
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = priv->pool;
+ Repo *repo;
+ int i;
+
+ FOR_REPOS(i, repo) {
+ auto hrepo = static_cast<HyRepo>(repo->appdata);
+ if (!hrepo)
+ continue;
+ libdnf::repoGetImpl(hrepo)->detachLibsolvRepo();
+ }
+ g_free(priv->cache_dir);
+ g_free(priv->arch);
+ queue_free(&priv->installonly);
+
+ free_map_fully(priv->pkg_excludes);
+ free_map_fully(priv->pkg_includes);
+ free_map_fully(priv->repo_excludes);
+ free_map_fully(priv->module_excludes);
+ free_map_fully(priv->module_includes);
+ free_map_fully(pool->considered);
+ free_map_fully(priv->pkg_solvables);
+ pool_free(priv->pool);
+ if (priv->moduleContainer) {
+ delete priv->moduleContainer;
+ }
+
+ G_OBJECT_CLASS(dnf_sack_parent_class)->finalize(object);
+}
+
+// log levels (see also SOLV_ERROR etc. in <solv/pool.h>)
+#define HY_LL_INFO (1 << 20)
+#define HY_LL_ERROR (1 << 21)
+
+static void
+log_cb(Pool *pool, void *cb_data, int level, const char *buf)
+{
+ /* just proxy this to the GLib logging handler */
+ switch(level) {
+ case HY_LL_INFO:
+ g_debug ("%s", buf);
+ break;
+ case HY_LL_ERROR:
+ g_warning ("%s", buf);
+ break;
+ default:
+ g_info ("%s", buf);
+ break;
+ }
+}
+
+/**
+ * dnf_sack_init:
+ **/
+static void
+dnf_sack_init(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->pool = pool_create();
+ pool_set_flag(priv->pool, POOL_FLAG_WHATPROVIDESWITHDISABLED, 1);
+ priv->running_kernel_id = -1;
+ priv->running_kernel_fn = running_kernel;
+ priv->considered_uptodate = TRUE;
+ priv->cmdline_repo = NULL;
+ priv->allow_vendor_change = TRUE;
+ queue_init(&priv->installonly);
+
+ /* logging up after this*/
+ pool_setdebugcallback(priv->pool, log_cb, sack);
+ pool_setdebugmask(priv->pool,
+ SOLV_ERROR | SOLV_FATAL | SOLV_WARN | SOLV_DEBUG_RESULT |
+ HY_LL_INFO | HY_LL_ERROR);
+}
+
+/**
+ * dnf_sack_class_init:
+ **/
+static void
+dnf_sack_class_init(DnfSackClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_sack_finalize;
+}
+
+/**
+ * dnf_sack_new:
+ *
+ * Creates a new #DnfSack.
+ *
+ * Returns:(transfer full): a #DnfSack
+ *
+ * Since: 0.7.0
+ **/
+DnfSack *
+dnf_sack_new(void)
+{
+ return DNF_SACK(g_object_new(DNF_TYPE_SACK, NULL));
+}
+
+// Try to load cached solv file into repo otherwise return FALSE
+static gboolean
+try_to_use_cached_solvfile(const char *path, Repo *repo, int flags, const unsigned char *checksum, GError **err){
+ FILE *fp_cache = fopen(path, "r");
+ if (!fp_cache) {
+ // Missing cache files (ENOENT) are not an error and can even be expected in some cases
+ // (such as when repo doesn't have updateinfo/prestodelta metadata).
+ // Use g_debug in order not to pollute the log by default with such entries.
+ if (errno == ENOENT) {
+ g_debug("Failed to open solvfile cache: %s: %s", path, strerror(errno));
+ } else {
+ g_warning("Failed to open solvfile cache: %s: %s", path, strerror(errno));
+ }
+ return FALSE;
+ }
+ std::unique_ptr<SolvUserdata, decltype(solv_free)*> solv_userdata = solv_userdata_read(fp_cache);
+ gboolean ret = TRUE;
+ if (solv_userdata && solv_userdata_verify(solv_userdata.get(), checksum)) {
+ // after reading the header rewind to the begining
+ fseek(fp_cache, 0, SEEK_SET);
+ if (repo_add_solv(repo, fp_cache, flags)) {
+ g_set_error (err,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("repo_add_solv() has failed."));
+ ret = FALSE;
+ }
+ } else {
+ ret = FALSE;
+ }
+
+ fclose(fp_cache);
+ return ret;
+}
+
+void
+dnf_sack_set_running_kernel_fn (DnfSack *sack, dnf_sack_running_kernel_fn_t fn)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->running_kernel_fn = fn;
+}
+
+void
+dnf_sack_set_pkg_solvables(DnfSack *sack, Map *pkg_solvables, int pool_nsolvables)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+
+ auto pkg_solvables_tmp = static_cast<Map *>(g_malloc(sizeof(Map)));
+ if (priv->pkg_solvables)
+ free_map_fully(priv->pkg_solvables);
+ map_init_clone(pkg_solvables_tmp, pkg_solvables);
+ priv->pkg_solvables = pkg_solvables_tmp;
+ priv->pool_nsolvables = pool_nsolvables;
+}
+
+int
+dnf_sack_get_pool_nsolvables(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->pool_nsolvables;
+}
+
+libdnf::PackageSet *
+dnf_sack_get_pkg_solvables(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return new libdnf::PackageSet(sack, priv->pkg_solvables);
+}
+
+/**
+ * dnf_sack_last_solvable: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Returns an ID of last solvable in sack
+ *
+ * Returns: an #Id
+ *
+ * Since: 0.7.0
+ */
+Id
+dnf_sack_last_solvable(DnfSack *sack)
+{
+ return dnf_sack_get_pool(sack)->nsolvables - 1;
+}
+
+void
+dnf_sack_recompute_considered_map(DnfSack * sack, Map ** considered, libdnf::Query::ExcludeFlags flags)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ if (!*considered) {
+ if ((static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES) ||
+ (!priv->repo_excludes && !priv->pkg_excludes && !priv->pkg_includes))
+ && (static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
+ || !priv->module_excludes)) {
+ return;
+ }
+ *considered = static_cast<Map *>(g_malloc0(sizeof(Map)));
+ map_init(*considered, pool->nsolvables);
+ } else
+ map_grow(*considered, pool->nsolvables);
+
+ // considered = (all - repo_excludes - pkg_excludes) and
+ // (pkg_includes + all_from_repos_not_using_includes)
+ map_setall(*considered);
+ dnf_sack_make_provides_ready(sack);
+ if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
+ && priv->module_excludes)
+ map_subtract(*considered, priv->module_excludes);
+ if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES)) {
+ if (priv->repo_excludes)
+ map_subtract(*considered, priv->repo_excludes);
+ if (priv->pkg_excludes)
+ map_subtract(*considered, priv->pkg_excludes);
+ if (priv->pkg_includes) {
+ map_grow(priv->pkg_includes, pool->nsolvables);
+ Map pkg_includes_tmp;
+ map_init_clone(&pkg_includes_tmp, priv->pkg_includes);
+
+ // Add all solvables from repositories which do not use "includes"
+ Id repoid;
+ Repo *repo;
+ FOR_REPOS(repoid, repo) {
+ auto hyrepo = static_cast<HyRepo>(repo->appdata);
+ if (!hyrepo->getUseIncludes()) {
+ Id solvableid;
+ Solvable *solvable;
+ FOR_REPO_SOLVABLES(repo, solvableid, solvable)
+ MAPSET(&pkg_includes_tmp, solvableid);
+ }
+ }
+
+ map_and(*considered, &pkg_includes_tmp);
+ map_free(&pkg_includes_tmp);
+ }
+ }
+}
+
+/**
+ * dnf_sack_recompute_considered:
+ * @sack: a #DnfSack instance.
+ *
+ * Recompute considered packages for libsolv and queries.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_recompute_considered(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ if (priv->considered_uptodate)
+ return;
+ dnf_sack_recompute_considered_map(
+ sack, &pool->considered, libdnf::Query::ExcludeFlags::APPLY_EXCLUDES);
+ priv->considered_uptodate = TRUE;
+}
+
+static gboolean
+load_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
+ const char *suffix, const char * which_filename,
+ int (*cb)(Repo *, FILE *), GError **error)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ int ret = 0;
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ Repo *repo = repoImpl->libsolvRepo;
+ const char *name = repo->name;
+ FILE *fp;
+ gboolean done = FALSE;
+
+ char *fn_cache = dnf_sack_give_cache_fn(sack, name, suffix);
+ assert(libdnf::repoGetImpl(hrepo)->checksum);
+
+ int flags = 0;
+ /* the updateinfo is not a real extension */
+ if (which_repodata != _HY_REPODATA_UPDATEINFO)
+ flags |= REPO_EXTEND_SOLVABLES;
+ /* do not pollute the main pool with directory component ids */
+ if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
+ flags |= REPO_LOCALPOOL;
+ if (try_to_use_cached_solvfile(fn_cache, repo, flags, libdnf::repoGetImpl(hrepo)->checksum, error)) {
+ g_debug("%s: using cache file: %s", __func__, fn_cache);
+ done = TRUE;
+ repo_update_state(hrepo, which_repodata, _HY_LOADED_CACHE);
+ repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
+ }
+ if (error && *error) {
+ g_prefix_error(error, _("Loading extension cache %s (%d) failed: "), fn_cache, which_repodata);
+ return FALSE;
+ }
+
+ g_free(fn_cache);
+ if (done)
+ return TRUE;
+
+ auto fn = hrepo->getMetadataPath(which_filename);
+ /* nothing set */
+ if (fn.empty()) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_NO_CAPABILITY,
+ _("no %1$s string for %2$s"),
+ which_filename, name);
+ return FALSE;
+ }
+
+ fp = solv_xfopen(fn.c_str(), "r");
+ if (fp == NULL) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("failed to open: %s"), fn.c_str());
+ return FALSE;
+ }
+ g_debug("%s: loading: %s", __func__, fn.c_str());
+
+ int previous_last = repo->nrepodata - 1;
+ ret = cb(repo, fp);
+ fclose(fp);
+ if (ret == 0) {
+ repo_update_state(hrepo, which_repodata, _HY_LOADED_FETCH);
+ assert(previous_last == repo->nrepodata - 2); (void)previous_last;
+ repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
+ }
+ priv->provides_ready = 0;
+ return TRUE;
+}
+
+static int
+load_filelists_cb(Repo *repo, FILE *fp)
+{
+ if (repo_add_rpmmd(repo, fp, "FL", REPO_EXTEND_SOLVABLES))
+ return DNF_ERROR_INTERNAL_ERROR;
+ return 0;
+}
+
+static int
+load_presto_cb(Repo *repo, FILE *fp)
+{
+ if (repo_add_deltainfoxml(repo, fp, 0))
+ return DNF_ERROR_INTERNAL_ERROR;
+ return 0;
+}
+
+static int
+load_updateinfo_cb(Repo *repo, FILE *fp)
+{
+ if (repo_add_updateinfoxml(repo, fp, 0))
+ return DNF_ERROR_INTERNAL_ERROR;
+ return 0;
+}
+
+static int
+load_other_cb(Repo *repo, FILE *fp)
+{
+ if (repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES))
+ return DNF_ERROR_INTERNAL_ERROR;
+ return 0;
+}
+
+static int
+repo_is_one_piece(Repo *repo)
+{
+ int i;
+ for (i = repo->start; i < repo->end; i++)
+ if (repo->pool->solvables[i].repo != repo)
+ return 0;
+ return 1;
+}
+
+static gboolean
+write_main(DnfSack *sack, HyRepo hrepo, int switchtosolv, GError **error)
+{
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ Repo *repo = repoImpl->libsolvRepo;
+ const char *name = repo->name;
+ const char *chksum = pool_checksum_str(dnf_sack_get_pool(sack), repoImpl->checksum);
+ char *fn = dnf_sack_give_cache_fn(sack, name, NULL);
+ char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
+ int tmp_fd = mkstemp(tmp_fn_templ);
+ gboolean ret = TRUE;
+ gint rc;
+
+ g_debug("caching repo: %s (0x%s)", name, chksum);
+
+ if (tmp_fd < 0) {
+ ret = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("cannot create temporary file: %s"),
+ tmp_fn_templ);
+ goto done;
+ } else {
+ FILE *fp = fdopen(tmp_fd, "w+");
+ if (!fp) {
+ ret = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("failed opening tmp file: %s"),
+ strerror(errno));
+ goto done;
+ }
+
+ SolvUserdata solv_userdata;
+ if (solv_userdata_fill(&solv_userdata, repoImpl->checksum, error)) {
+ ret = FALSE;
+ fclose(fp);
+ goto done;
+ }
+
+ Repowriter *writer = repowriter_create(repo);
+ repowriter_set_userdata(writer, &solv_userdata, solv_userdata_size);
+ rc = repowriter_write(writer, fp);
+ repowriter_free(writer);
+ if (rc) {
+ ret = FALSE;
+ fclose(fp);
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("While writing primary cache %s repowriter write failed: %i, error: %s"),
+ tmp_fn_templ, rc, pool_errstr(repo->pool));
+ goto done;
+ }
+
+ if (fclose(fp)) {
+ ret = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("Failed closing tmp file %s: %s"),
+ tmp_fn_templ, strerror(errno));
+ goto done;
+ }
+ }
+ if (switchtosolv && repo_is_one_piece(repo)) {
+ repo_empty(repo, 1);
+ /* switch over to written solv file activate paging */
+ gboolean loaded = try_to_use_cached_solvfile(tmp_fn_templ, repo, 0, repoImpl->checksum, error);
+ if (error && *error) {
+ g_prefix_error(error, _("Failed to use newly written primary cache: %s: "), tmp_fn_templ);
+ ret = FALSE;
+ goto done;
+ }
+ if (!loaded) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("Failed to use newly written primary cache: %s"), tmp_fn_templ);
+ ret = FALSE;
+ goto done;
+ }
+ }
+
+ ret = mv(tmp_fn_templ, fn, error);
+ if (!ret)
+ goto done;
+ repoImpl->state_main = _HY_WRITTEN;
+
+ done:
+ if (!ret && tmp_fd >= 0)
+ unlink(tmp_fn_templ);
+ g_free(tmp_fn_templ);
+ g_free(fn);
+ return ret;
+}
+
+/* this filter makes sure only the updateinfo repodata is written */
+static int
+write_ext_updateinfo_filter(Repo *repo, Repokey *key, void *kfdata)
+{
+ auto data = static_cast<Repodata *>(kfdata);
+ if (key->name == 1 && (int) key->size != data->repodataid)
+ return -1;
+ return repo_write_stdkeyfilter(repo, key, 0);
+}
+
+static gboolean
+write_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
+ const char *suffix, GError **error)
+{
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ Repo *repo = repoImpl->libsolvRepo;
+ int ret = 0;
+ const char *name = repo->name;
+
+ Id repodata = repo_get_repodata(hrepo, which_repodata);
+ assert(repodata);
+ Repodata *data = repo_id2repodata(repo, repodata);
+ char *fn = dnf_sack_give_cache_fn(sack, name, suffix);
+ char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
+ int tmp_fd = mkstemp(tmp_fn_templ);
+ gboolean success;
+ if (tmp_fd < 0) {
+ success = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("can not create temporary file %s"),
+ tmp_fn_templ);
+ goto done;
+ } else {
+ FILE *fp = fdopen(tmp_fd, "w+");
+
+ g_debug("%s: storing %s to: %s", __func__, repo->name, tmp_fn_templ);
+
+ SolvUserdata solv_userdata;
+ if (solv_userdata_fill(&solv_userdata, repoImpl->checksum, error)) {
+ fclose(fp);
+ success = FALSE;
+ goto done;
+ }
+
+ Repowriter *writer = repowriter_create(repo);
+ repowriter_set_userdata(writer, &solv_userdata, solv_userdata_size);
+ if (which_repodata != _HY_REPODATA_UPDATEINFO) {
+ repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1);
+ repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE);
+ ret = repowriter_write(writer, fp);
+ } else {
+ // write only updateinfo repodata
+ int oldstart = repo->start;
+ repo->start = repoImpl->main_end;
+ repo->nsolvables -= repoImpl->main_nsolvables;
+ repowriter_set_flags(writer, REPOWRITER_LEGACY);
+ repowriter_set_keyfilter(writer, write_ext_updateinfo_filter, data);
+ repowriter_set_keyqueue(writer, 0);
+ ret = repowriter_write(writer, fp);
+ repo->start = oldstart;
+ repo->nsolvables += repoImpl->main_nsolvables;
+ }
+ repowriter_free(writer);
+ if (ret) {
+ success = FALSE;
+ fclose(fp);
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("While writing extension cache %s (%d): repowriter write failed: %i, error: %s"),
+ tmp_fn_templ, which_repodata, ret, pool_errstr(repo->pool));
+ goto done;
+ }
+
+ if (fclose(fp)) {
+ success = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("While writing extension cache (%d): cannot close temporary file: %s"),
+ which_repodata, tmp_fn_templ);
+ goto done;
+ }
+ }
+
+ if (repo_is_one_piece(repo) && which_repodata != _HY_REPODATA_UPDATEINFO) {
+ /* switch over to written solv file activate paging */
+ int flags = REPO_USE_LOADING | REPO_EXTEND_SOLVABLES;
+ /* do not pollute the main pool with directory component ids */
+ if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
+ flags |= REPO_LOCALPOOL;
+ repodata_extend_block(data, repo->start, repo->end - repo->start);
+ data->state = REPODATA_LOADING;
+ int loaded = try_to_use_cached_solvfile(tmp_fn_templ, repo, flags, repoImpl->checksum, error);
+ if (error && *error) {
+ g_prefix_error(error, _("Failed to use newly written extension cache: %s (%d): "),
+ tmp_fn_templ, which_repodata);
+ success = FALSE;
+ goto done;
+ }
+ if (!loaded) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("Failed to use newly written extension cache: %s (%d)"), tmp_fn_templ, which_repodata);
+ success = FALSE;
+ goto done;
+ }
+
+ data->state = REPODATA_AVAILABLE;
+ }
+
+ if (!mv(tmp_fn_templ, fn, error)) {
+ success = FALSE;
+ goto done;
+ }
+ repo_update_state(hrepo, which_repodata, _HY_WRITTEN);
+ success = TRUE;
+ done:
+ if (ret && tmp_fd >=0 )
+ unlink(tmp_fn_templ);
+ g_free(tmp_fn_templ);
+ g_free(fn);
+ return success;
+}
+
+static gboolean
+load_yum_repo(DnfSack *sack, HyRepo hrepo, GError **error)
+{
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ gboolean retval = TRUE;
+ Pool *pool = priv->pool;
+ const char *name = hrepo->getId().c_str();
+ Repo *repo = repo_create(pool, name);
+ const char *fn_repomd = repoImpl->repomdFn.c_str();
+ char *fn_cache = dnf_sack_give_cache_fn(sack, name, NULL);
+
+ FILE *fp_primary = NULL;
+ FILE *fp_repomd = NULL;
+
+ if (!fn_repomd) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("null repo md file"));
+ retval = FALSE;
+ goto out;
+ }
+ fp_repomd = fopen(fn_repomd, "r");
+ if (fp_repomd == NULL) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("can not read file %1$s: %2$s"),
+ fn_repomd, strerror(errno));
+ retval = FALSE;
+ goto out;
+ }
+ checksum_fp(repoImpl->checksum, fp_repomd);
+
+ if (try_to_use_cached_solvfile(fn_cache, repo, 0, repoImpl->checksum, error)) {
+ const char *chksum = pool_checksum_str(pool, repoImpl->checksum);
+ g_debug("using cached %s (0x%s)", name, chksum);
+ repoImpl->state_main = _HY_LOADED_CACHE;
+ goto out;
+ }
+
+ if (error && *error) {
+ g_prefix_error(error, _("While loading repository failed to use %s: "), fn_cache);
+ retval = FALSE;
+ goto out;
+ } else {
+ auto primary = hrepo->getMetadataPath(MD_TYPE_PRIMARY);
+ if (primary.empty()) {
+ // It could happen when repomd file has no "primary" data or they are in unsupported
+ // format like zchunk
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("loading of MD_TYPE_PRIMARY has failed."));
+ retval = FALSE;
+ goto out;
+ }
+ fp_primary = solv_xfopen(primary.c_str(), "r");
+ if (fp_primary == 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Opening repository primary data has failed: %s"),
+ strerror(errno));
+ retval = FALSE;
+ goto out;
+ }
+
+ g_debug("Loading repomd: %s", fn_repomd);
+ if (repo_add_repomdxml(repo, fp_repomd, 0)) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Loading repomd has failed: %s"),
+ pool_errstr(repo->pool));
+ retval = FALSE;
+ goto out;
+ }
+
+ g_debug("Loading primary: %s", primary.c_str());
+ if (repo_add_rpmmd(repo, fp_primary, 0, 0)) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Loading primary has failed: %s"),
+ pool_errstr(repo->pool));
+ retval = FALSE;
+ goto out;
+ }
+ repoImpl->state_main = _HY_LOADED_FETCH;
+ }
+out:
+ if (fp_repomd)
+ fclose(fp_repomd);
+ if (fp_primary)
+ fclose(fp_primary);
+ g_free(fn_cache);
+
+ if (retval) {
+ libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
+ priv->provides_ready = 0;
+ } else
+ repo_free(repo, 1);
+ return retval;
+}
+
+/**
+ * dnf_sack_set_cachedir:
+ * @sack: a #DnfSack instance.
+ * @value: a a filesystem path.
+ *
+ * Sets the location to store the metadata cache files.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_cachedir (DnfSack *sack, const gchar *value)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ g_free (priv->cache_dir);
+ priv->cache_dir = g_strdup(value);
+}
+
+/**
+ * dnf_sack_set_arch:
+ * @sack: a #DnfSack instance.
+ * @value: an architecture, e.g. "i386", or %NULL for autodetection.
+ * @error: a #GError or %NULL.
+ *
+ * Sets the system architecture to use for the sack. Calling this
+ * function is optional before a dnf_sack_setup() call.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_sack_set_arch (DnfSack *sack, const gchar *value, GError **error) try
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char *arch = value;
+ g_autofree gchar *detected = NULL;
+
+ /* autodetect */
+ if (arch == NULL) {
+ if (hy_detect_arch(&detected)) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to auto-detect architecture"));
+ return FALSE;
+ }
+ arch = detected;
+ }
+
+ g_debug("Architecture is: %s", arch);
+ g_free (priv->arch);
+ priv->arch = g_strdup(arch);
+ pool_setdisttype(pool, DISTTYPE_RPM);
+ pool_setarch(pool, arch);
+
+ /* Since one of commits after 0.6.20 libsolv allowes custom arches
+ * which means it will be 'newcoolarch' and 'noarch' always. */
+ priv->have_set_arch = TRUE;
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_sack_set_all_arch:
+ * @sack: a #DnfSack instance.
+ * @all_arch: new value for all_arch property.
+ *
+ * This is used for controlling whether an arch needs to
+ * be set within libsolv or not.
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_all_arch (DnfSack *sack, gboolean all_arch)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->all_arch = all_arch;
+}
+
+/**
+ * dnf_sack_get_all_arch
+ * @sack: a #DnfSack instance.
+ *
+ * Returns: the state of all_arch.
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_sack_get_all_arch (DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->all_arch;
+}
+
+/*
+ * dnf_sack_set_allow_vendor_change:
+ * @sack: a #DnfSack instance.
+ * @allow_vendor_change is a boolean.
+ *
+ * Sets the value of allow vendor change to use for
+ * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.54.3
+ *
+ * */
+void
+dnf_sack_set_allow_vendor_change(DnfSack *sack, gboolean allow_vendor_change)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->allow_vendor_change = allow_vendor_change;
+}
+
+/*
+ * dnf_sack_get_allow_vendor_change:
+ * @sack: a #DnfSack instance.
+ * @allow_vendor_change is a boolean.
+ *
+ * Gets the value of allow vendor change to use for
+ * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
+ *
+ * Returns: True if flag set to 1, False if set to 0
+ *
+ * Since: 0.54.3
+ *
+ * */
+gboolean
+dnf_sack_get_allow_vendor_change(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->allow_vendor_change;
+}
+
+/**
+ * dnf_sack_get_arch
+ * @sack: a #DnfSack instance.
+ *
+ * Returns: the state of all_arch.
+ *
+ * Since: 0.16.2
+ */
+const char *
+dnf_sack_get_arch (DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->arch;
+}
+
+/**
+ * dnf_sack_set_rootdir:
+ * @sack: a #DnfSack instance.
+ * @value: a directory path, or %NULL.
+ *
+ * Sets the install root location.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_rootdir (DnfSack *sack, const gchar *value)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ pool_set_rootdir(priv->pool, value);
+ /* Don't look for running kernels if we're not operating live on
+ * the current system.
+ */
+ if (g_strcmp0(value, "/") != 0)
+ priv->running_kernel_fn = NULL;
+}
+
+/**
+ * dnf_sack_setup:
+ * @sack: a #DnfSack instance.
+ * @flags: optional flags, e.g. %DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR.
+ * @error: a #GError or %NULL.
+ *
+ * Sets up a new package sack, the fundamental hawkey structure.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_sack_setup(DnfSack *sack, int flags, GError **error) try
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ /* we never called dnf_sack_set_cachedir() */
+ if (priv->cache_dir == NULL) {
+ if (geteuid() != 0) {
+ char *username = this_username();
+ char *path = pool_tmpjoin(pool, DEFAULT_CACHE_USER, "-", username);
+ path = pool_tmpappend(pool, path, "-", "XXXXXX");
+ priv->cache_dir = g_strdup(path);
+ g_free(username);
+ } else {
+ priv->cache_dir = g_strdup(DEFAULT_CACHE_ROOT);
+ }
+ }
+
+ /* create the directory */
+ if (flags & DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR) {
+ if (mkcachedir(priv->cache_dir)) {
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("failed creating cachedir %s"),
+ priv->cache_dir);
+ return FALSE;
+ }
+ }
+
+ /* never called dnf_sack_set_arch(), so autodetect */
+ if (!priv->have_set_arch && !priv->all_arch) {
+ if (!dnf_sack_set_arch (sack, NULL, error))
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_sack_evr_cmp:
+ * @sack: a #DnfSack instance.
+ * @evr1: an EVR string.
+ * @evr2: another EVR string.
+ *
+ * Compares one EVR with another using the sack.
+ *
+ * Returns: 0 for equality
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_sack_evr_cmp(DnfSack *sack, const char *evr1, const char *evr2)
+{
+ g_autoptr(DnfSack) _sack = NULL;
+ if (!sack)
+ _sack = dnf_sack_new ();
+ else
+ _sack = static_cast<DnfSack *>(g_object_ref(sack));
+ return pool_evrcmp_str(dnf_sack_get_pool(_sack), evr1, evr2, EVRCMP_COMPARE);
+}
+
+/**
+ * dnf_sack_get_cache_dir:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the cache directory.
+ *
+ * Returns: The user-set cache-dir, or %NULL for not set
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_sack_get_cache_dir(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->cache_dir;
+}
+
+/**
+ * dnf_sack_get_running_kernel:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the running kernel.
+ *
+ * Returns: a #DnfPackage, or %NULL
+ *
+ * Since: 0.7.0
+ */
+DnfPackage *
+dnf_sack_get_running_kernel(DnfSack *sack)
+{
+ Id id = dnf_sack_running_kernel(sack);
+ if (id < 0)
+ return NULL;
+ return dnf_package_new(sack, id);
+}
+
+/**
+ * dnf_sack_give_cache_fn:
+ * @sack: a #DnfSack instance.
+ * @reponame: a repo name.
+ * @ext: a file extension
+ *
+ * Gets a cache filename.
+ *
+ * Returns: a filename
+ *
+ * Since: 0.7.0
+ */
+char *
+dnf_sack_give_cache_fn(DnfSack *sack, const char *reponame, const char *ext)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ assert(reponame);
+ char *fn = solv_dupjoin(priv->cache_dir, "/", reponame);
+ if (ext)
+ return solv_dupappend(fn, ext, ".solvx");
+ return solv_dupappend(fn, ".solv", NULL);
+}
+
+/**
+ * dnf_sack_list_arches:
+ * @sack: a #DnfSack instance.
+ *
+ * Creates list of architectures
+ *
+ * Returns: a list of architectures
+ *
+ * Since: 0.7.0
+ */
+const char **
+dnf_sack_list_arches(DnfSack *sack)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ const int BLOCK_SIZE = 31;
+ int c = 0;
+ const char **ss = NULL;
+
+ if (!(pool->id2arch && pool->lastarch))
+ return NULL;
+
+ for (Id id = 0; id <= pool->lastarch; ++id) {
+ if (!pool->id2arch[id])
+ continue;
+ ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
+ ss[c++] = pool_id2str(pool, id);
+ }
+ ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
+ ss[c++] = NULL;
+ return ss;
+}
+
+/**
+ * dnf_sack_set_installonly:
+ * @sack: a #DnfSack instance.
+ * @installonly: an array of package names.
+ *
+ * Sets the packages to use for installonlyn.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_installonly(DnfSack *sack, const char **installonly)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ const char *name;
+
+ queue_empty(&priv->installonly);
+ if (installonly == NULL)
+ return;
+ while ((name = *installonly++) != NULL)
+ queue_pushunique(&priv->installonly, pool_str2id(priv->pool, name, 1));
+}
+
+/**
+ * dnf_sack_get_installonly: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the installonlyn packages.
+ *
+ * Returns: a Queue
+ *
+ * Since: 0.7.0
+ */
+Queue *
+dnf_sack_get_installonly(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return &priv->installonly;
+}
+
+/**
+ * dnf_sack_set_installonly_limit:
+ * @sack: a #DnfSack instance.
+ * @limit: a the number of packages.
+ *
+ * Sets the installonly limit.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_installonly_limit(DnfSack *sack, guint limit)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->installonly_limit = limit;
+}
+
+/**
+ * dnf_sack_get_installonly_limit:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the installonly limit.
+ *
+ * Returns: integer value
+ *
+ * Since: 0.7.0
+ */
+guint
+dnf_sack_get_installonly_limit(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->installonly_limit;
+}
+
+static Repo *
+dnf_sack_setup_cmdline_repo(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ if (!priv->cmdline_repo) {
+ HyRepo hrepo = hy_repo_create(HY_CMDLINE_REPO_NAME);
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ Repo *repo = repo_create(dnf_sack_get_pool(sack), HY_CMDLINE_REPO_NAME);
+ repo->appdata = hrepo;
+ repoImpl->libsolvRepo = repo;
+ repoImpl->needs_internalizing = 1;
+ priv->cmdline_repo = repo;
+ }
+ return priv->cmdline_repo;
+}
+
+DnfPackage *
+dnf_sack_add_cmdline_package_flags(DnfSack *sack, const char *fn, const int flags)
+{
+ if (!is_readable_rpm(fn)) {
+ g_warning("not a readable RPM file: %s, skipping", fn);
+ return NULL;
+ }
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Repo *repo = dnf_sack_setup_cmdline_repo(sack);
+ Id p;
+ priv->provides_ready = 0; /* triggers internalizing later */
+ p = repo_add_rpm(repo, fn, flags);
+ if (p == 0) {
+ g_warning ("failed to read RPM: %s, skipping",
+ pool_errstr (dnf_sack_get_pool (sack)));
+ return NULL;
+ }
+ auto hrepo = static_cast<HyRepo>(repo->appdata);
+ libdnf::repoGetImpl(hrepo)->needs_internalizing = 1;
+ priv->considered_uptodate = FALSE; /* triggers recompute_considered later */
+ return dnf_package_new(sack, p);
+}
+
+/**
+ * dnf_sack_add_cmdline_package:
+ * @sack: a #DnfSack instance.
+ * @fn: a filename.
+ *
+ * Adds the given .rpm file to the command line repo.
+ *
+ * Returns: a #DnfPackage, or %NULL
+ *
+ * Since: 0.7.0
+ */
+DnfPackage *
+dnf_sack_add_cmdline_package(DnfSack *sack, const char *fn)
+{
+ return dnf_sack_add_cmdline_package_flags(sack, fn,
+ REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|
+ RPM_ADD_WITH_HDRID|RPM_ADD_WITH_SHA256SUM);
+}
+
+DnfPackage *
+dnf_sack_add_cmdline_package_nochecksum(DnfSack *sack, const char *fn)
+{
+ return dnf_sack_add_cmdline_package_flags(sack, fn,
+ REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+}
+
+/**
+ * dnf_sack_count:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the number of items in the sack.
+ *
+ * Returns: number of solvables.
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_sack_count(DnfSack *sack)
+{
+ int cnt = 0;
+ Id p;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ FOR_PKG_SOLVABLES(p)
+ cnt++;
+ return cnt;
+}
+
+static void
+dnf_sack_add_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
+{
+ Map *destmap = *dest;
+ if (destmap == NULL) {
+ destmap = static_cast<Map *>(g_malloc0(sizeof(Map)));
+ Pool *pool = dnf_sack_get_pool(sack);
+ map_init(destmap, pool->nsolvables);
+ *dest = destmap;
+ }
+
+ auto pkgmap = pkgset->getMap();
+ map_or(destmap, pkgmap);
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->considered_uptodate = FALSE;
+}
+
+/**
+ * dnf_sack_add_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Adds excludes to the sack.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_add_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_add_excludes_or_includes(sack, &priv->pkg_excludes, pset);
+}
+
+/**
+ * dnf_sack_add_module_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Adds excludes to the sack.
+ *
+ * Since: 0.13.4
+ */
+void
+dnf_sack_add_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_add_excludes_or_includes(sack, &priv->module_excludes, pset);
+}
+
+/**
+ * dnf_sack_add_includes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Add includes to the sack.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_add_includes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_add_excludes_or_includes(sack, &priv->pkg_includes, pset);
+}
+
+static void
+dnf_sack_remove_excludes_or_includes(DnfSack *sack, Map *from, const DnfPackageSet *pkgset)
+{
+ if (from == NULL)
+ return;
+ auto pkgmap = pkgset->getMap();
+ map_subtract(from, pkgmap);
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->considered_uptodate = FALSE;
+}
+
+/**
+ * dnf_sack_remove_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Removes excludes from the sack.
+ *
+ * Since: 0.9.4
+ */
+void
+dnf_sack_remove_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_remove_excludes_or_includes(sack, priv->pkg_excludes, pset);
+}
+
+/**
+ * dnf_sack_remove_module_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Removes excludes from the sack.
+ *
+ * Since: 0.13.4
+ */
+void
+dnf_sack_remove_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_remove_excludes_or_includes(sack, priv->module_excludes, pset);
+}
+
+/**
+ * dnf_sack_remove_includes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Removes includes from the sack.
+ *
+ * Since: 0.9.4
+ */
+void
+dnf_sack_remove_includes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_remove_excludes_or_includes(sack, priv->pkg_includes, pset);
+}
+
+static void
+dnf_sack_set_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
+{
+ if (*dest == NULL && pkgset == NULL)
+ return;
+
+ *dest = free_map_fully(*dest);
+ if (pkgset) {
+ *dest = static_cast<Map *>(g_malloc0(sizeof(Map)));
+ auto pkgmap = pkgset->getMap();
+ map_init_clone(*dest, pkgmap);
+ }
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->considered_uptodate = FALSE;
+}
+
+void
+dnf_sack_set_module_includes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ if (!pset) {
+ return;
+ }
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ free_map_fully(priv->module_includes);
+ priv->module_includes = static_cast<Map *>(g_malloc0(sizeof(Map)));
+ auto pkgmap = pset->getMap();
+ map_init_clone(priv->module_includes, pkgmap);
+}
+
+/**
+ * dnf_sack_set_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Set excludes for the sack.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_set_excludes_or_includes(sack, &priv->pkg_excludes, pset);
+}
+
+/**
+ * dnf_sack_set_module_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Set excludes for the sack.
+ *
+ * Since: 0.13.4
+ */
+void
+dnf_sack_set_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_set_excludes_or_includes(sack, &priv->module_excludes, pset);
+}
+
+/**
+ * dnf_sack_set_includes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Set any sack includes.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_set_includes(DnfSack *sack, const DnfPackageSet *pset)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ dnf_sack_set_excludes_or_includes(sack, &priv->pkg_includes, pset);
+}
+
+/**
+ * dnf_sack_reset_excludes:
+ * @sack: a #DnfSack instance.
+ *
+ * Reset excludes (remove excludes map from memory).
+ *
+ * Since: 0.9.4
+ */
+void
+dnf_sack_reset_excludes(DnfSack *sack)
+{
+ dnf_sack_set_excludes(sack, NULL);
+}
+
+/**
+ * dnf_sack_reset_module_excludes:
+ * @sack: a #DnfSack instance.
+ *
+ * Reset excludes (remove excludes map from memory).
+ *
+ * Since: 0.13.4
+ */
+void
+dnf_sack_reset_module_excludes(DnfSack *sack)
+{
+ dnf_sack_set_module_excludes(sack, NULL);
+}
+
+/**
+ * dnf_sack_reset_includes:
+ * @sack: a #DnfSack instance.
+ *
+ * Reset includes (remove includes map from memory).
+ *
+ * Since: 0.9.4
+ */
+void
+dnf_sack_reset_includes(DnfSack *sack)
+{
+ dnf_sack_set_includes(sack, NULL);
+}
+
+/**
+ * dnf_sack_get_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Gets sack excludes.
+ *
+ * Since: 0.9.4
+ */
+DnfPackageSet *
+dnf_sack_get_excludes(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Map *excl = priv->pkg_excludes;
+ return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
+}
+
+/**
+ * dnf_sack_get_module_excludes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Gets sack excludes.
+ *
+ * Since: 0.13.4
+ */
+DnfPackageSet *
+dnf_sack_get_module_excludes(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Map *excl = priv->module_excludes;
+ return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
+}
+
+/**
+ * dnf_sack_get_module_includes:
+ * @sack: a #DnfSack instance.
+ * @pset: a #DnfPackageSet or %NULL.
+ *
+ * Since: 0.16.1
+ */
+DnfPackageSet *
+dnf_sack_get_module_includes(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Map *excl = priv->module_includes;
+ return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
+}
+
+/**
+ * dnf_sack_get_includes:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets sack includes.
+ *
+ * Since: 0.9.4
+ */
+DnfPackageSet *
+dnf_sack_get_includes(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Map *incl = priv->pkg_includes;
+ return incl ? dnf_packageset_from_bitmap(sack, incl) : NULL;
+}
+
+/**
+ * dnf_sack_set_use_includes:
+ * @sack: a #DnfSack instance.
+ * @repo_name: a name of repo or %NULL for all repos.
+ * @enabled: a use includes for a repo or all repos.
+ *
+ * Enable/disable usage of includes for repo/all-repos.
+ *
+ * Returns: FALSE if error occurred (unknown reponame) else TRUE.
+ *
+ * Since: 0.9.4
+ */
+gboolean
+dnf_sack_set_use_includes(DnfSack *sack, const char *reponame, gboolean enabled)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ if (reponame) {
+ HyRepo hyrepo = hrepo_by_name(sack, reponame);
+ if (!hyrepo)
+ return FALSE;
+ if (hyrepo->getUseIncludes() != enabled)
+ {
+ hyrepo->setUseIncludes(enabled);
+ priv->considered_uptodate = FALSE;
+ }
+ } else {
+ Id repoid;
+ Repo *repo;
+ FOR_REPOS(repoid, repo) {
+ auto hyrepo = static_cast<HyRepo>(pool->repos[repoid]->appdata);
+ if (hyrepo->getUseIncludes() != enabled)
+ {
+ hyrepo->setUseIncludes(enabled);
+ priv->considered_uptodate = FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * dnf_sack_set_provides_not_ready:
+ * @sack: a #DnfSack instance.
+ *
+ * Mark sack to recompute provides
+ *
+ * Since: 0.16.3
+ */
+void
+dnf_sack_set_provides_not_ready(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->provides_ready = FALSE;
+}
+
+/**
+ * dnf_sack_set_considered_to_update:
+ * @sack: a #DnfSack instance.
+ *
+ * Mark sack to recompute considered
+ *
+ * Since: 0.16.3
+ */
+void
+dnf_sack_set_considered_to_update(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ priv->considered_uptodate = FALSE;
+}
+
+/**
+ * dnf_sack_get_use_includes:
+ * @sack: a #DnfSack instance.
+ * @repo_name: a name of repo or %NULL for all repos.
+ * @enabled: a returned state of includes for repo
+ *
+ * Enable/disable usage of includes for repo/all-repos.
+ *
+ * Returns: FALSE if error occurred (unknown reponame) else TRUE.
+ *
+ * Since: 0.9.4
+ */
+gboolean
+dnf_sack_get_use_includes(DnfSack *sack, const char *reponame, gboolean *enabled)
+{
+ assert(reponame);
+ HyRepo hyrepo = hrepo_by_name(sack, reponame);
+ if (!hyrepo)
+ return FALSE;
+ *enabled = hyrepo->getUseIncludes();
+ return TRUE;
+}
+
+/**
+ * dnf_sack_repo_enabled:
+ * @sack: a #DnfSack instance.
+ * @reponame: a repo name.
+ * @enabled: the enabled state.
+ *
+ * Enable repository
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_sack_repo_enabled(DnfSack *sack, const char *reponame, int enabled)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ Repo *repo = repo_by_name(sack, reponame);
+ Map *excl = priv->repo_excludes;
+
+ if (repo == NULL)
+ return DNF_ERROR_INTERNAL_ERROR;
+ if (excl == NULL) {
+ excl = static_cast<Map *>(g_malloc0(sizeof(Map)));
+ map_init(excl, pool->nsolvables);
+ priv->repo_excludes = excl;
+ }
+ repo->disabled = !enabled;
+ priv->provides_ready = 0;
+
+ Id p;
+ Solvable *s;
+ if (repo->disabled)
+ FOR_REPO_SOLVABLES(repo, p, s)
+ MAPSET(priv->repo_excludes, p);
+ else
+ FOR_REPO_SOLVABLES(repo, p, s)
+ MAPCLR(priv->repo_excludes, p);
+ priv->considered_uptodate = FALSE;
+ return 0;
+}
+
+/**
+ * dnf_sack_load_system_repo:
+ * @sack: a #DnfSack instance.
+ * @a_hrepo: a rpmdb repo.
+ * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
+ * @error: a #GError or %NULL.
+ *
+ * Loads the rpmdb into the sack.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_sack_load_system_repo(DnfSack *sack, HyRepo a_hrepo, int flags, GError **error) try
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ gboolean ret = TRUE;
+ HyRepo hrepo = a_hrepo;
+ Repo *repo;
+
+ if (hrepo) {
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ repoImpl->id = HY_SYSTEM_REPO_NAME;
+ repoImpl->conf->name().set(libdnf::Option::Priority::RUNTIME, HY_SYSTEM_REPO_NAME);
+ } else
+ hrepo = hy_repo_create(HY_SYSTEM_REPO_NAME);
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+
+ repoImpl->load_flags = flags &= ~DNF_SACK_LOAD_FLAG_BUILD_CACHE;
+
+ repo = repo_create(pool, HY_SYSTEM_REPO_NAME);
+
+ g_debug("fetching rpmdb");
+ int flagsrpm = REPO_REUSE_REPODATA | RPM_ADD_WITH_HDRID | REPO_USE_ROOTDIR;
+ int rc = repo_add_rpmdb_reffp(repo, NULL, flagsrpm);
+ if (!rc) {
+ repoImpl->state_main = _HY_LOADED_FETCH;
+ } else {
+ repo_free(repo, 1);
+ ret = FALSE;
+ g_set_error (error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("failed loading RPMDB"));
+ goto finish;
+ }
+
+ libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
+ pool_set_installed(pool, repo);
+ priv->provides_ready = 0;
+
+ repoImpl->main_nsolvables = repo->nsolvables;
+ repoImpl->main_nrepodata = repo->nrepodata;
+ repoImpl->main_end = repo->end;
+ priv->considered_uptodate = FALSE;
+
+ finish:
+ if (a_hrepo == NULL)
+ hy_repo_free(hrepo);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_sack_load_repo:
+ * @sack: a #DnfSack instance.
+ * @repo: a #HyRepo.
+ * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
+ * @error: a #GError, or %NULL.
+ *
+ * Loads a remote repo into the sack.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_sack_load_repo(DnfSack *sack, HyRepo repo, int flags, GError **error) try
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ GError *error_local = NULL;
+ const int build_cache = flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE;
+ gboolean retval;
+ if (!load_yum_repo(sack, repo, error))
+ return FALSE;
+ repoImpl->load_flags = flags;
+ if (repoImpl->state_main == _HY_LOADED_FETCH && build_cache) {
+ if (!write_main(sack, repo, 1, error))
+ return FALSE;
+ }
+ repoImpl->main_nsolvables = repoImpl->libsolvRepo->nsolvables;
+ repoImpl->main_nrepodata = repoImpl->libsolvRepo->nrepodata;
+ repoImpl->main_end = repoImpl->libsolvRepo->end;
+ if (flags & DNF_SACK_LOAD_FLAG_USE_FILELISTS) {
+ retval = load_ext(sack, repo, _HY_REPODATA_FILENAMES,
+ HY_EXT_FILENAMES, MD_TYPE_FILELISTS,
+ load_filelists_cb, &error_local);
+ /* allow missing files */
+ if (!retval) {
+ if (g_error_matches (error_local,
+ DNF_ERROR,
+ DNF_ERROR_NO_CAPABILITY)) {
+ g_debug("no filelists metadata available for %s", repoImpl->conf->name().getValue().c_str());
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ return FALSE;
+ }
+ }
+ if (repoImpl->state_filelists == _HY_LOADED_FETCH && build_cache) {
+ if (!write_ext(sack, repo,
+ _HY_REPODATA_FILENAMES,
+ HY_EXT_FILENAMES, error))
+ return FALSE;
+ }
+ }
+ if (flags & DNF_SACK_LOAD_FLAG_USE_OTHER) {
+ retval = load_ext(sack, repo, _HY_REPODATA_OTHER,
+ HY_EXT_OTHER, MD_TYPE_OTHER,
+ load_other_cb, &error_local);
+ /* allow missing files */
+ if (!retval) {
+ if (g_error_matches (error_local,
+ DNF_ERROR,
+ DNF_ERROR_NO_CAPABILITY)) {
+ g_debug("no other metadata available for %s", repoImpl->conf->name().getValue().c_str());
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ return FALSE;
+ }
+ }
+ if (repoImpl->state_other == _HY_LOADED_FETCH && build_cache) {
+ if (!write_ext(sack, repo,
+ _HY_REPODATA_OTHER,
+ HY_EXT_OTHER, error))
+ return FALSE;
+ }
+ }
+ if (flags & DNF_SACK_LOAD_FLAG_USE_PRESTO) {
+ retval = load_ext(sack, repo, _HY_REPODATA_PRESTO,
+ HY_EXT_PRESTO, MD_TYPE_PRESTODELTA,
+ load_presto_cb, &error_local);
+ if (!retval) {
+ if (g_error_matches (error_local,
+ DNF_ERROR,
+ DNF_ERROR_NO_CAPABILITY)) {
+ g_debug("no presto metadata available for %s", repoImpl->conf->name().getValue().c_str());
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ return FALSE;
+ }
+ }
+ if (repoImpl->state_presto == _HY_LOADED_FETCH && build_cache)
+ if (!write_ext(sack, repo, _HY_REPODATA_PRESTO, HY_EXT_PRESTO, error))
+ return FALSE;
+ }
+ /* updateinfo must come *after* all other extensions, as it is not a real
+ extension, but contains a new set of packages */
+ if (flags & DNF_SACK_LOAD_FLAG_USE_UPDATEINFO) {
+ retval = load_ext(sack, repo, _HY_REPODATA_UPDATEINFO,
+ HY_EXT_UPDATEINFO, MD_TYPE_UPDATEINFO,
+ load_updateinfo_cb, &error_local);
+ /* allow missing files */
+ if (!retval) {
+ if (g_error_matches (error_local,
+ DNF_ERROR,
+ DNF_ERROR_NO_CAPABILITY)) {
+ g_debug("no updateinfo available for %s", repoImpl->conf->name().getValue().c_str());
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ return FALSE;
+ }
+ }
+ if (repoImpl->state_updateinfo == _HY_LOADED_FETCH && build_cache)
+ if (!write_ext(sack, repo, _HY_REPODATA_UPDATEINFO, HY_EXT_UPDATEINFO, error))
+ return FALSE;
+ }
+ priv->considered_uptodate = FALSE;
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+// internal to hawkey
+
+// return true if q1 is a superset of q2
+// only works if there are no duplicates both in q1 and q2
+// the map parameter must point to an empty map that can hold all ids
+// (it is also returned empty)
+static int
+is_superset(Queue *q1, Queue *q2, Map *m)
+{
+ int i, cnt = 0;
+ for (i = 0; i < q2->count; i++)
+ MAPSET(m, q2->elements[i]);
+ for (i = 0; i < q1->count; i++)
+ if (MAPTST(m, q1->elements[i]))
+ cnt++;
+ for (i = 0; i < q2->count; i++)
+ MAPCLR(m, q2->elements[i]);
+ return cnt == q2->count;
+}
+
+
+static void
+rewrite_repos(DnfSack *sack, Queue *addedfileprovides,
+ Queue *addedfileprovides_inst)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int i;
+
+ Map providedids;
+ map_init(&providedids, pool->ss.nstrings);
+
+ Queue fileprovidesq;
+ queue_init(&fileprovidesq);
+
+ Repo *repo;
+ FOR_REPOS(i, repo) {
+ auto hrepo = static_cast<HyRepo>(repo->appdata);
+ if (!hrepo)
+ continue;
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ if (!(repoImpl->load_flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE))
+ continue;
+ if (repoImpl->main_nrepodata < 2)
+ continue;
+ /* now check if the repo already contains all of our file provides */
+ Queue *addedq = repo == pool->installed && addedfileprovides_inst ?
+ addedfileprovides_inst : addedfileprovides;
+ if (!addedq->count)
+ continue;
+ Repodata *data = repo_id2repodata(repo, 1);
+ queue_empty(&fileprovidesq);
+ if (repodata_lookup_idarray(data, SOLVID_META,
+ REPOSITORY_ADDEDFILEPROVIDES,
+ &fileprovidesq)) {
+ if (is_superset(&fileprovidesq, addedq, &providedids))
+ continue;
+ }
+ repodata_set_idarray(data, SOLVID_META,
+ REPOSITORY_ADDEDFILEPROVIDES, addedq);
+ repodata_internalize(data);
+ /* re-write main data only */
+ int oldnrepodata = repo->nrepodata;
+ int oldnsolvables = repo->nsolvables;
+ int oldend = repo->end;
+ repo->nrepodata = repoImpl->main_nrepodata;
+ repo->nsolvables = repoImpl->main_nsolvables;
+ repo->end = repoImpl->main_end;
+ g_debug("rewriting repo: %s", repo->name);
+ write_main(sack, hrepo, 0, NULL);
+ repo->nrepodata = oldnrepodata;
+ repo->nsolvables = oldnsolvables;
+ repo->end = oldend;
+ }
+ queue_free(&fileprovidesq);
+ map_free(&providedids);
+}
+
+/**
+ * dnf_sack_make_provides_ready:
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the sack ready for depsolving.
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_sack_make_provides_ready(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+
+ if (priv->provides_ready)
+ return;
+ repo_internalize_all_trigger(priv->pool);
+ Queue addedfileprovides;
+ Queue addedfileprovides_inst;
+ queue_init(&addedfileprovides);
+ queue_init(&addedfileprovides_inst);
+ pool_addfileprovides_queue(priv->pool, &addedfileprovides,
+ &addedfileprovides_inst);
+ if (addedfileprovides.count || addedfileprovides_inst.count)
+ rewrite_repos(sack, &addedfileprovides, &addedfileprovides_inst);
+ queue_free(&addedfileprovides);
+ queue_free(&addedfileprovides_inst);
+ pool_createwhatprovides(priv->pool);
+ priv->provides_ready = 1;
+}
+
+/**
+ * dnf_sack_running_kernel: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Returns the ID of the running kernel.
+ *
+ * Returns: an #Id or 0
+ *
+ * Since: 0.7.0
+ */
+Id
+dnf_sack_running_kernel(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ if (priv->running_kernel_id >= 0)
+ return priv->running_kernel_id;
+ if (priv->running_kernel_fn)
+ priv->running_kernel_id = priv->running_kernel_fn(sack);
+ return priv->running_kernel_id;
+}
+
+/**
+ * dnf_sack_get_pool: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the internal pool for the sack.
+ *
+ * Returns: The pool, which is always set
+ *
+ * Since: 0.7.0
+ */
+Pool *
+dnf_sack_get_pool(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->pool;
+}
+
+/**
+ * dnf_sack_set_module_container: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Sets the internal ModulePackageContainer.
+ *
+ * Returns: The old ModulePackageContainer, that has to be freed manually.
+ *
+ * Since: 0.31.0
+ */
+libdnf::ModulePackageContainer *
+dnf_sack_set_module_container(DnfSack *sack, libdnf::ModulePackageContainer * newConteiner)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ auto oldConteiner = priv->moduleContainer;
+ priv->moduleContainer = newConteiner;
+ return oldConteiner;
+}
+
+/**
+ * dnf_sack_get_module_container: (skip)
+ * @sack: a #DnfSack instance.
+ *
+ * Gets the internal ModulePackageContainer.
+ *
+ * Returns: The ModulePackageContainer, that can be not set
+ *
+ * Since: 0.16.3
+ */
+libdnf::ModulePackageContainer *
+dnf_sack_get_module_container(DnfSack *sack)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ return priv->moduleContainer;
+}
+
+/**********************************************************************/
+
+static void
+process_excludes(DnfSack *sack, GPtrArray *enabled_repos)
+{
+ auto & mainConf = libdnf::getGlobalMainConfig();
+ auto & disabled = mainConf.disable_excludes().getValue();
+
+ if (std::find(disabled.begin(), disabled.end(), "all") != disabled.end()) {
+ return;
+ }
+
+ libdnf::PackageSet repoIncludes(sack);
+ libdnf::PackageSet repoExcludes(sack);
+ bool includesExist = false;
+
+ for (guint i = 0; i < enabled_repos->len; i++) {
+ auto dnfRepo = static_cast<DnfRepo *>(enabled_repos->pdata[i]);
+ auto repo = dnf_repo_get_repo(dnfRepo);
+ if (std::find(disabled.begin(), disabled.end(), repo->getId()) != disabled.end()) {
+ continue;
+ }
+
+ libdnf::Query repoQuery(sack);
+ repoQuery.addFilter(HY_PKG_REPONAME, HY_EQ, repo->getId().c_str());
+ repoQuery.apply();
+
+ for (const auto & name : repo->getConfig()->includepkgs().getValue()) {
+ libdnf::Query query(repoQuery);
+ auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
+ if (ret.first) {
+ repoIncludes += *query.runSet();
+ includesExist = true;
+ repo->setUseIncludes(true);
+ }
+ }
+
+ for (const auto & name : repo->getConfig()->excludepkgs().getValue()) {
+ libdnf::Query query(repoQuery);
+ auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
+ if (ret.first) {
+ repoExcludes += *query.runSet();
+ }
+ }
+ }
+
+ if (std::find(disabled.begin(), disabled.end(), "main") == disabled.end()) {
+ bool useGlobalIncludes = false;
+ for (const auto & name : mainConf.includepkgs().getValue()) {
+ libdnf::Query query(sack);
+ auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
+ if (ret.first) {
+ repoIncludes += *query.runSet();
+ includesExist = true;
+ useGlobalIncludes = true;
+ }
+ }
+
+ for (const auto & name : mainConf.excludepkgs().getValue()) {
+ libdnf::Query query(sack);
+ auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
+ if (ret.first) {
+ repoExcludes += *query.runSet();
+ }
+ }
+
+ if (useGlobalIncludes) {
+ dnf_sack_set_use_includes(sack, nullptr, true);
+ }
+ }
+
+ if (includesExist) {
+ dnf_sack_add_includes(sack, &repoIncludes);
+ }
+ dnf_sack_add_excludes(sack, &repoExcludes);
+}
+
+/**
+ * dnf_sack_add_repo:
+ */
+gboolean
+dnf_sack_add_repo(DnfSack *sack,
+ DnfRepo *repo,
+ guint permissible_cache_age,
+ DnfSackAddFlags flags,
+ DnfState *state,
+ GError **error) try
+{
+ gboolean ret = TRUE;
+ GError *error_local = NULL;
+ DnfState *state_local;
+ int flags_hy = DNF_SACK_LOAD_FLAG_BUILD_CACHE;
+
+ /* set state */
+ ret = dnf_state_set_steps(state, error,
+ 5, /* check repo */
+ 95, /* load solv */
+ -1);
+ if (!ret)
+ return FALSE;
+
+ /* check repo */
+ state_local = dnf_state_get_child(state);
+ ret = dnf_repo_check(repo,
+ permissible_cache_age,
+ state_local,
+ &error_local);
+ if (!ret) {
+ g_debug("failed to check, attempting update: %s",
+ error_local->message);
+ g_clear_error(&error_local);
+ dnf_state_reset(state_local);
+ ret = dnf_repo_update(repo,
+ DNF_REPO_UPDATE_FLAG_FORCE,
+ state_local,
+ &error_local);
+ if (!ret) {
+ if (!dnf_repo_get_required(repo) &&
+ (g_error_matches(error_local,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_FETCH_SOURCE) ||
+ g_error_matches(error_local,
+ DNF_ERROR,
+ DNF_ERROR_REPO_NOT_AVAILABLE))) {
+ g_warning("Skipping refresh of %s: %s",
+ dnf_repo_get_id(repo),
+ error_local->message);
+ g_error_free(error_local);
+ return dnf_state_finished(state, error);
+ }
+ g_propagate_error(error, error_local);
+ return FALSE;
+ }
+ }
+
+ /* checking disabled the repo */
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE) {
+ g_debug("Skipping %s as repo no longer enabled",
+ dnf_repo_get_id(repo));
+ return dnf_state_finished(state, error);
+ }
+
+ /* done */
+ if (!dnf_state_done(state, error))
+ return FALSE;
+
+ /* only load what's required */
+ if ((flags & DNF_SACK_ADD_FLAG_FILELISTS) > 0)
+ flags_hy |= DNF_SACK_LOAD_FLAG_USE_FILELISTS;
+ if ((flags & DNF_SACK_ADD_FLAG_OTHER) > 0)
+ flags_hy |= DNF_SACK_LOAD_FLAG_USE_OTHER;
+ if ((flags & DNF_SACK_ADD_FLAG_UPDATEINFO) > 0)
+ flags_hy |= DNF_SACK_LOAD_FLAG_USE_UPDATEINFO;
+
+ /* load solv */
+ g_debug("Loading repo %s", dnf_repo_get_id(repo));
+ dnf_state_action_start(state, DNF_STATE_ACTION_LOADING_CACHE, NULL);
+ if (!dnf_sack_load_repo(sack, dnf_repo_get_repo(repo), flags_hy, error))
+ return FALSE;
+
+ /* done */
+ return dnf_state_done(state, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_sack_add_repos:
+ */
+gboolean
+dnf_sack_add_repos(DnfSack *sack,
+ GPtrArray *repos,
+ guint permissible_cache_age,
+ DnfSackAddFlags flags,
+ DnfState *state,
+ GError **error) try
+{
+ gboolean ret;
+ guint cnt = 0;
+ guint i;
+ DnfRepo *repo;
+ DnfState *state_local;
+ g_autoptr(GPtrArray) enabled_repos = g_ptr_array_new();
+
+ /* count the enabled repos */
+ for (i = 0; i < repos->len; i++) {
+ repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
+ continue;
+
+ /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
+ if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
+ continue;
+ }
+
+ cnt++;
+ }
+
+ /* add each repo */
+ dnf_state_set_number_steps(state, cnt);
+ for (i = 0; i < repos->len; i++) {
+ repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
+ continue;
+
+ /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
+ if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
+ if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
+ continue;
+ }
+
+ state_local = dnf_state_get_child(state);
+ ret = dnf_sack_add_repo(sack,
+ repo,
+ permissible_cache_age,
+ flags,
+ state_local,
+ error);
+ if (!ret)
+ return FALSE;
+
+ g_ptr_array_add(enabled_repos, repo);
+
+ /* done */
+ if (!dnf_state_done(state, error))
+ return FALSE;
+ }
+
+ process_excludes(sack, enabled_repos);
+
+ /* success */
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+namespace {
+void readModuleMetadataFromRepo(DnfSack * sack, libdnf::ModulePackageContainer * modulePackages,
+ const char * platformModule)
+{
+ modulePackages->add(sack);
+ modulePackages->loadFailSafeData();
+ if (!modulePackages->empty()) {
+ // TODO remove hard-coded path
+ try {
+ std::vector<std::string> paths{"/etc/os-release", "/usr/lib/os-release"};
+ modulePackages->addPlatformPackage(sack, paths, platformModule);
+ } catch (const std::exception & except) {
+ auto logger(libdnf::Log::getLogger());
+ logger->critical("Detection of Platform Module failed: " + std::string(except.what()));
+ }
+ }
+}
+
+/// @return std::map<name:stream.arch, std::vector<std::string>>
+static std::map<std::string, std::vector<std::string>> getDemodularizedRpms(
+ libdnf::ModulePackageContainer & moduleContainer, const std::vector<libdnf::ModulePackage *> & allPackages)
+{
+ std::map<std::string, std::vector<std::string>> ret;
+ auto latest = moduleContainer.getLatestModules(allPackages, true);
+ for (auto modulePackage : latest) {
+ auto demodularized = modulePackage->getDemodularizedRpms();
+ if (demodularized.empty()) {
+ continue;
+ }
+ std::string packageID{modulePackage->getNameStream()};
+ packageID.append(".");
+ packageID.append(modulePackage->getArch());
+ auto & data = ret[packageID];
+ data.insert(data.end(), demodularized.begin(), demodularized.end());
+ }
+ return ret;
+}
+
+/// Return <includeNEVRAs>, <excludeNEVRAs>, <names>, <srcNames>, <name dependency container>
+static std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, libdnf::DependencyContainer>
+collectNevraForInclusionExclusion(DnfSack *sack, libdnf::ModulePackageContainer &modulePackageContainer)
+{
+ auto allPackages = modulePackageContainer.getModulePackages();
+ auto demodularizedNames = getDemodularizedRpms(modulePackageContainer, allPackages);
+
+ std::vector<std::string> includeNEVRAs;
+ std::vector<std::string> excludeNEVRAs;
+ std::vector<std::string> names;
+ std::vector<std::string> srcNames;
+ libdnf::DependencyContainer nameDependencies{sack};
+ libdnf::Nevra nevra;
+ // TODO: turn into std::vector<const char *> to prevent unnecessary conversion?
+ for (const auto & module : allPackages) {
+ auto artifacts = module->getArtifacts();
+ // TODO use Goal::listInstalls() to not requires filtering out Platform
+ if (modulePackageContainer.isModuleActive(module->getId())) {
+ std::string packageID{module->getNameStream()};
+ packageID.append(".");
+ packageID.append(module->getArch());
+ auto it = demodularizedNames.find(packageID);
+ if (it == demodularizedNames.end()) {
+ for (const auto &rpm : artifacts) {
+ if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
+ auto arch = nevra.getArch();
+ // source packages do not provide anything and must not cause excluding binary packages
+ if (arch == "src" || arch == "nosrc") {
+ srcNames.push_back(nevra.getName());
+ } else {
+ names.push_back(nevra.getName());
+ nameDependencies.addReldep(nevra.getName().c_str());
+ }
+ }
+ }
+ } else {
+ for (const auto &rpm : artifacts) {
+ if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
+ bool found = false;
+ for ( auto & demodularized : it->second) {
+ if (nevra.getName() == demodularized) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ continue;
+ }
+ auto arch = nevra.getArch();
+ // source packages do not provide anything and must not cause excluding binary packages
+ if (arch == "src" || arch == "nosrc") {
+ srcNames.push_back(nevra.getName());
+ } else {
+ names.push_back(nevra.getName());
+ nameDependencies.addReldep(nevra.getName().c_str());
+ }
+ }
+ }
+ }
+ copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(includeNEVRAs));
+ } else {
+ copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(excludeNEVRAs));
+ }
+ }
+
+ return std::make_tuple(std::move(includeNEVRAs), std::move(excludeNEVRAs), std::move(names), std::move(srcNames),
+ std::move(nameDependencies));
+}
+
+void
+setModuleExcludes(DnfSack * sack, const char ** hotfixRepos, libdnf::ModulePackageContainer & modulePackageContainer)
+{
+ dnf_sack_set_module_excludes(sack, nullptr);
+
+ auto data = collectNevraForInclusionExclusion(sack, modulePackageContainer);
+
+ auto & includeNEVRAs = std::get<0>(data);
+ auto & excludeNEVRAs = std::get<1>(data);
+ auto & names = std::get<2>(data);
+ auto & srcNames = std::get<3>(data);
+ auto & nameDependencies = std::get<4>(data);
+
+ std::vector<const char *> namesCString(names.size() + 1);
+ std::vector<const char *> srcNamesCString(srcNames.size() + 1);
+ std::vector<const char *> excludeNEVRAsCString(excludeNEVRAs.size() + 1);
+ std::vector<const char *> includeNEVRAsCString(includeNEVRAs.size() + 1);
+
+ transform(names.begin(), names.end(), namesCString.begin(), std::mem_fn(&std::string::c_str));
+ transform(srcNames.begin(), srcNames.end(), srcNamesCString.begin(), std::mem_fn(&std::string::c_str));
+ transform(excludeNEVRAs.begin(), excludeNEVRAs.end(), excludeNEVRAsCString.begin(),
+ std::mem_fn(&std::string::c_str));
+ transform(includeNEVRAs.begin(), includeNEVRAs.end(), includeNEVRAsCString.begin(),
+ std::mem_fn(&std::string::c_str));
+
+ libdnf::Query keepPackages{sack};
+ const char *keepRepo[] = {HY_CMDLINE_REPO_NAME, HY_SYSTEM_REPO_NAME, nullptr};
+ keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, keepRepo);
+ if (hotfixRepos != nullptr) {
+ keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, hotfixRepos);
+ }
+
+ libdnf::Query includeQuery{sack};
+ libdnf::Query excludeQuery{keepPackages};
+ libdnf::Query excludeProvidesQuery{keepPackages};
+ libdnf::Query excludeNamesQuery(keepPackages);
+ libdnf::Query excludeSrcNamesQuery(keepPackages);
+ includeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, includeNEVRAsCString.data());
+
+ excludeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, excludeNEVRAsCString.data());
+ excludeQuery.queryDifference(includeQuery);
+
+ // Exclude packages by their Provides
+ excludeProvidesQuery.addFilter(HY_PKG_PROVIDES, &nameDependencies);
+ excludeProvidesQuery.queryDifference(includeQuery);
+
+ // Search for source packages with same names as included source artifacts
+ excludeSrcNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, srcNamesCString.data());
+ const char * srcArchs[] = {"src", "nosrc", nullptr};
+ excludeSrcNamesQuery.addFilter(HY_PKG_ARCH, HY_EQ, srcArchs);
+
+ // Required to filtrate out source packages and packages with incompatible architectures
+ excludeNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, namesCString.data());
+ excludeNamesQuery.queryUnion(excludeSrcNamesQuery);
+ excludeNamesQuery.queryDifference(includeQuery);
+
+ dnf_sack_set_module_excludes(sack, excludeQuery.getResultPset());
+ dnf_sack_add_module_excludes(sack, excludeProvidesQuery.getResultPset());
+ dnf_sack_add_module_excludes(sack, excludeNamesQuery.getResultPset());
+ dnf_sack_set_module_includes(sack, includeQuery.getResultPset());
+}
+
+}
+
+std::vector<libdnf::ModulePackage *> requiresModuleEnablement(
+ DnfSack * sack, const libdnf::PackageSet * installSet)
+{
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ if (!priv->module_includes || !priv->moduleContainer) {
+ return {};
+ }
+ libdnf::PackageSet tmp(sack);
+ tmp += *const_cast<libdnf::PackageSet*>(installSet);
+ tmp /= priv->module_includes;
+
+ if (tmp.empty()) {
+ return {};
+ }
+ auto toEnable = priv->moduleContainer->requiresModuleEnablement(*installSet);
+ return toEnable;
+}
+
+void dnf_sack_filter_modules(DnfSack *sack, GPtrArray *repos, const char *install_root,
+ const char * platformModule)
+{
+ std::vector<const char *> hotfixRepos;
+ // don't filter RPMs from repos with the 'module_hotfixes' flag set
+ for (unsigned int i = 0; i < repos->len; i++) {
+ auto repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
+ if (dnf_repo_get_module_hotfixes(repo)) {
+ hotfixRepos.push_back(dnf_repo_get_id(repo));
+ }
+ }
+ hotfixRepos.push_back(nullptr);
+ dnf_sack_filter_modules_v2(sack, nullptr, hotfixRepos.data(), install_root, platformModule,
+ false, false, false);
+}
+
+std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer::ModuleErrorType> dnf_sack_filter_modules_v2(
+ DnfSack * sack, DnfModulePackageContainer * moduleContainer, const char ** hotfixRepos,
+ const char * install_root, const char * platformModule, bool updateOnly, bool debugSolver, bool applyObsoletes)
+{
+ if (!updateOnly) {
+ if (!install_root) {
+ throw std::runtime_error("Installroot not provided");
+ }
+ DnfSackPrivate *priv = GET_PRIVATE(sack);
+ if (!moduleContainer) {
+ if (priv->moduleContainer) {
+ delete priv->moduleContainer;
+ }
+ priv->moduleContainer = new libdnf::ModulePackageContainer(dnf_sack_get_all_arch(sack),
+ install_root, dnf_sack_get_arch(sack));
+ moduleContainer = priv->moduleContainer;
+ }
+ readModuleMetadataFromRepo(sack, moduleContainer, platformModule);
+ moduleContainer->addDefaultsFromDisk();
+
+ try {
+ moduleContainer->moduleDefaultsResolve();
+ } catch (libdnf::ModulePackageContainer::ResolveException & exception) {
+ auto logger(libdnf::Log::getLogger());
+ logger->debug(tfm::format(_("No module defaults found: %s"), exception.what()));
+ }
+ }
+
+ if (!moduleContainer) {
+ throw std::runtime_error("ModuleContainer not provided");
+ }
+
+ if (applyObsoletes) {
+ moduleContainer->applyObsoletes();
+ }
+ auto ret = moduleContainer->resolveActiveModulePackages(debugSolver);
+
+ setModuleExcludes(sack, hotfixRepos, *moduleContainer);
+ return ret;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2015 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_SACK_H
+#define __DNF_SACK_H
+
+#include <glib-object.h>
+
+#include "hy-types.h"
+#include "dnf-sack.h"
+#include "dnf-repo.h"
+#include "dnf-state.h"
+#include "hy-packageset.h"
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_SACK (dnf_sack_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfSack, dnf_sack, DNF, SACK, GObject)
+
+struct _DnfSackClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+/**
+ * DnfSackSetupFlags:
+ * @DNF_SACK_SETUP_FLAG_NONE: No flags set
+ * @DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR: Create the cache dir if required
+ *
+ * Flags to use when setting up the sack.
+ **/
+typedef enum {
+ DNF_SACK_SETUP_FLAG_NONE = 0,
+ DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR = 1 << 0,
+ /*< private >*/
+ DNF_SACK_SETUP_FLAG_LAST
+} DnfSackSetupFlags;
+
+/**
+ * DnfSackAddFlags:
+ * @DNF_SACK_LOAD_FLAG_NONE: No flags set
+ * @DNF_SACK_LOAD_FLAG_BUILD_CACHE: Build the solv cache if required
+ * @DNF_SACK_LOAD_FLAG_USE_FILELISTS: Use the filelists metadata
+ * @DNF_SACK_LOAD_FLAG_USE_PRESTO: Use presto deltas metadata
+ * @DNF_SACK_LOAD_FLAG_USE_UPDATEINFO: Use updateinfo metadata
+ * @DNF_SACK_LOAD_FLAG_USE_OTHER: Use other metadata
+ *
+ * Flags to use when loading from the sack.
+ **/
+typedef enum {
+ DNF_SACK_LOAD_FLAG_NONE = 0,
+ DNF_SACK_LOAD_FLAG_BUILD_CACHE = 1 << 0,
+ DNF_SACK_LOAD_FLAG_USE_FILELISTS = 1 << 1,
+ DNF_SACK_LOAD_FLAG_USE_PRESTO = 1 << 2,
+ DNF_SACK_LOAD_FLAG_USE_UPDATEINFO = 1 << 3,
+ DNF_SACK_LOAD_FLAG_USE_OTHER = 1 << 4,
+ /*< private >*/
+ DNF_SACK_LOAD_FLAG_LAST
+} DnfSackLoadFlags;
+
+DnfSack *dnf_sack_new (void);
+
+void dnf_sack_set_cachedir (DnfSack *sack,
+ const gchar *value);
+gboolean dnf_sack_set_arch (DnfSack *sack,
+ const gchar *value,
+ GError **error);
+void dnf_sack_set_all_arch (DnfSack *sack,
+ gboolean all_arch);
+gboolean dnf_sack_get_all_arch (DnfSack *sack);
+void dnf_sack_set_allow_vendor_change(DnfSack *sack,
+ gboolean allow_vendor_change);
+gboolean dnf_sack_get_allow_vendor_change(DnfSack *sack);
+void dnf_sack_set_rootdir (DnfSack *sack,
+ const gchar *value);
+gboolean dnf_sack_setup (DnfSack *sack,
+ int flags,
+ GError **error);
+int dnf_sack_evr_cmp (DnfSack *sack,
+ const char *evr1,
+ const char *evr2);
+const char *dnf_sack_get_cache_dir (DnfSack *sack);
+DnfPackage *dnf_sack_get_running_kernel (DnfSack *sack);
+char *dnf_sack_give_cache_fn (DnfSack *sack,
+ const char *reponame,
+ const char *ext);
+const char **dnf_sack_list_arches (DnfSack *sack);
+void dnf_sack_set_installonly (DnfSack *sack,
+ const char **installonly);
+void dnf_sack_set_installonly_limit (DnfSack *sack,
+ guint limit);
+guint dnf_sack_get_installonly_limit (DnfSack *sack);
+DnfPackage *dnf_sack_add_cmdline_package (DnfSack *sack,
+ const char *fn);
+DnfPackage *dnf_sack_add_cmdline_package_nochecksum(DnfSack *sack,
+ const char *fn);
+int dnf_sack_count (DnfSack *sack);
+void dnf_sack_add_excludes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_add_module_excludes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_add_includes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_remove_excludes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_remove_module_excludes(DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_remove_includes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_set_excludes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_set_module_excludes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_set_module_includes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_set_includes (DnfSack *sack,
+ const DnfPackageSet *pset);
+void dnf_sack_reset_excludes (DnfSack *sack);
+void dnf_sack_reset_module_excludes (DnfSack *sack);
+void dnf_sack_reset_includes (DnfSack *sack);
+DnfPackageSet *dnf_sack_get_includes (DnfSack *sack);
+DnfPackageSet *dnf_sack_get_excludes (DnfSack *sack);
+DnfPackageSet *dnf_sack_get_module_excludes (DnfSack *sack);
+DnfPackageSet *dnf_sack_get_module_includes (DnfSack *sack);
+gboolean dnf_sack_set_use_includes (DnfSack *sack,
+ const char *reponame,
+ gboolean enabled);
+gboolean dnf_sack_get_use_includes (DnfSack *sack,
+ const char *reponame,
+ gboolean *enabled);
+int dnf_sack_repo_enabled (DnfSack *sack,
+ const char *reponame,
+ int enabled);
+gboolean dnf_sack_load_system_repo (DnfSack *sack,
+ HyRepo a_hrepo,
+ int flags,
+ GError **error);
+gboolean dnf_sack_load_repo (DnfSack *sack,
+ HyRepo hrepo,
+ int flags,
+ GError **error);
+Pool *dnf_sack_get_pool (DnfSack *sack);
+
+void dnf_sack_filter_modules(DnfSack *sack, GPtrArray *repos, const char *install_root,
+ const char * platformModule);
+
+
+/**********************************************************************/
+
+/**
+ * DnfSackAddFlags:
+ * @DNF_SACK_ADD_FLAG_NONE: Add the primary
+ * @DNF_SACK_ADD_FLAG_FILELISTS: Add the filelists
+ * @DNF_SACK_ADD_FLAG_UPDATEINFO: Add the updateinfo
+ * @DNF_SACK_ADD_FLAG_REMOTE: Use remote repos
+ * @DNF_SACK_ADD_FLAG_UNAVAILABLE: Add repos that are unavailable
+ * @DNF_SACK_ADD_FLAG_OTHER: Add the other
+ *
+ * Flags to control repo loading into the sack.
+ **/
+typedef enum {
+ DNF_SACK_ADD_FLAG_NONE = 0,
+ DNF_SACK_ADD_FLAG_FILELISTS = 1 << 0,
+ DNF_SACK_ADD_FLAG_UPDATEINFO = 1 << 1,
+ DNF_SACK_ADD_FLAG_REMOTE = 1 << 2,
+ DNF_SACK_ADD_FLAG_UNAVAILABLE = 1 << 3,
+ DNF_SACK_ADD_FLAG_OTHER = 1 << 4,
+ /*< private >*/
+ DNF_SACK_ADD_FLAG_LAST
+} DnfSackAddFlags;
+
+gboolean dnf_sack_add_repo (DnfSack *sack,
+ DnfRepo *repo,
+ guint permissible_cache_age,
+ DnfSackAddFlags flags,
+ DnfState *state,
+ GError **error);
+gboolean dnf_sack_add_repos (DnfSack *sack,
+ GPtrArray *repos,
+ guint permissible_cache_age,
+ DnfSackAddFlags flags,
+ DnfState *state,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_SACK_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2009-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Most of this code was taken from Zif, libzif/zif-state.c
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-state
+ * @short_description: Progress reporting
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * Objects can use dnf_state_set_percentage() if the absolute percentage
+ * is known. Percentages should always go up, not down.
+ *
+ * Modules usually set the number of steps that are expected using
+ * dnf_state_set_number_steps() and then after each section is completed,
+ * the dnf_state_done() function should be called. This will automatically
+ * call dnf_state_set_percentage() with the correct values.
+ *
+ * #DnfState allows sub-modules to be "chained up" to the parent module
+ * so that as the sub-module progresses, so does the parent.
+ * The child can be reused for each section, and chains can be deep.
+ *
+ * To get a child object, you should use dnf_state_get_child() and then
+ * use the result in any sub-process. You should ensure that the child
+ * is not re-used without calling dnf_state_done().
+ *
+ * There are a few nice touches in this module, so that if a module only has
+ * one progress step, the child progress is used for updates.
+ *
+ * <example>
+ * <title>Using a #DnfState.</title>
+ * <programlisting>
+ * static void
+ * _do_something(DnfState *state)
+ * {
+ * DnfState *state_local;
+ *
+ * // setup correct number of steps
+ * dnf_state_set_number_steps(state, 2);
+ *
+ * // we can't cancel this function
+ * dnf_state_set_allow_cancel(state, FALSE);
+ *
+ * // run a sub function
+ * state_local = dnf_state_get_child(state);
+ * _do_something_else1(state_local);
+ *
+ * // this section done
+ * dnf_state_done(state);
+ *
+ * // run another sub function
+ * state_local = dnf_state_get_child(state);
+ * _do_something_else2(state_local);
+ *
+ * // this section done(all complete)
+ * dnf_state_done(state);
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * See also: #DnfLock
+ */
+
+
+#include "catch-error.hpp"
+#include "dnf-state.h"
+#include "dnf-utils.h"
+
+#include "utils/bgettext/bgettext-lib.h"
+
+typedef struct
+{
+ gboolean allow_cancel;
+ gboolean allow_cancel_changed_state;
+ gboolean allow_cancel_child;
+ gboolean enable_profile;
+ gboolean report_progress;
+ GCancellable *cancellable;
+ gchar *action_hint;
+ gchar *id;
+ gdouble *step_profile;
+ GTimer *timer;
+ guint64 speed;
+ guint64 *speed_data;
+ guint current;
+ guint last_percentage;
+ guint *step_data;
+ guint steps;
+ gulong action_child_id;
+ gulong package_progress_child_id;
+ gulong notify_speed_child_id;
+ gulong allow_cancel_child_id;
+ gulong percentage_child_id;
+ DnfStateAction action;
+ DnfStateAction last_action;
+ DnfStateAction child_action;
+ DnfState *child;
+ DnfState *parent;
+ GPtrArray *lock_ids;
+ DnfLock *lock;
+} DnfStatePrivate;
+
+enum {
+ SIGNAL_PERCENTAGE_CHANGED,
+ SIGNAL_SUBPERCENTAGE_CHANGED,
+ SIGNAL_ALLOW_CANCEL_CHANGED,
+ SIGNAL_ACTION_CHANGED,
+ SIGNAL_PACKAGE_PROGRESS_CHANGED,
+ SIGNAL_LAST
+};
+
+enum {
+ PROP_0,
+ PROP_SPEED,
+ PROP_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfState, dnf_state, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfStatePrivate *>(dnf_state_get_instance_private (o)))
+
+#define DNF_STATE_SPEED_SMOOTHING_ITEMS 5
+
+/**
+ * dnf_state_finalize:
+ **/
+static void
+dnf_state_finalize(GObject *object)
+{
+ DnfState *state = DNF_STATE(object);
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ /* no more locks */
+ dnf_state_release_locks(state);
+
+ dnf_state_reset(state);
+ g_free(priv->id);
+ g_free(priv->action_hint);
+ g_free(priv->step_data);
+ g_free(priv->step_profile);
+ if (priv->cancellable != NULL)
+ g_object_unref(priv->cancellable);
+ g_timer_destroy(priv->timer);
+ g_free(priv->speed_data);
+ g_ptr_array_unref(priv->lock_ids);
+ g_object_unref(priv->lock);
+
+ G_OBJECT_CLASS(dnf_state_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_state_init:
+ **/
+static void
+dnf_state_init(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ priv->allow_cancel = TRUE;
+ priv->allow_cancel_child = TRUE;
+ priv->action = DNF_STATE_ACTION_UNKNOWN;
+ priv->last_action = DNF_STATE_ACTION_UNKNOWN;
+ priv->timer = g_timer_new();
+ priv->lock_ids = g_ptr_array_new();
+ priv->report_progress = TRUE;
+ priv->lock = dnf_lock_new();
+ priv->speed_data = g_new0(guint64, DNF_STATE_SPEED_SMOOTHING_ITEMS);
+}
+
+/**
+ * dnf_state_get_property:
+ **/
+static void
+dnf_state_get_property(GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ DnfState *state = DNF_STATE(object);
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ switch(prop_id) {
+ case PROP_SPEED:
+ g_value_set_uint64(value, priv->speed);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * dnf_state_set_property:
+ **/
+static void
+dnf_state_set_property(GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ DnfState *state = DNF_STATE(object);
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ switch(prop_id) {
+ case PROP_SPEED:
+ priv->speed = g_value_get_uint64(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+/**
+ * dnf_state_class_init:
+ **/
+static void
+dnf_state_class_init(DnfStateClass *klass)
+{
+ GParamSpec *pspec;
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_state_finalize;
+ object_class->get_property = dnf_state_get_property;
+ object_class->set_property = dnf_state_set_property;
+
+ /**
+ * DnfState:speed:
+ **/
+ pspec = g_param_spec_uint64("speed", NULL, NULL,
+ 0, G_MAXUINT64, 0,
+ G_PARAM_READABLE);
+ g_object_class_install_property(object_class, PROP_SPEED, pspec);
+
+ signals [SIGNAL_PERCENTAGE_CHANGED] =
+ g_signal_new("percentage-changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfStateClass, percentage_changed),
+ NULL, NULL, g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+
+ signals [SIGNAL_ALLOW_CANCEL_CHANGED] =
+ g_signal_new("allow-cancel-changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfStateClass, allow_cancel_changed),
+ NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+ signals [SIGNAL_ACTION_CHANGED] =
+ g_signal_new("action-changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfStateClass, action_changed),
+ NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+ signals [SIGNAL_PACKAGE_PROGRESS_CHANGED] =
+ g_signal_new("package-progress-changed",
+ G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(DnfStateClass, package_progress_changed),
+ NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT);
+}
+
+/**
+ * dnf_state_set_report_progress:
+ * @state: A #DnfState
+ * @report_progress: if we care about percentage status
+ *
+ * This disables progress tracking for DnfState. This is generally a bad
+ * thing to do, except when you know you cannot guess the number of steps
+ * in the state.
+ *
+ * Using this function also reduced the amount of time spent getting a
+ * child state using dnf_state_get_child() as a refcounted version of
+ * the parent is returned instead. *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_report_progress(DnfState *state, gboolean report_progress)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ priv->report_progress = report_progress;
+}
+
+/**
+ * dnf_state_set_enable_profile:
+ * @state: A #DnfState
+ * @enable_profile: if profiling should be enabled
+ *
+ * This enables profiling of DnfState. This may be useful in development,
+ * but be warned; enabling profiling makes #DnfState very slow.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_enable_profile(DnfState *state, gboolean enable_profile)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ priv->enable_profile = enable_profile;
+}
+
+/**
+ * dnf_state_take_lock:
+ * @state: A #DnfState
+ * @lock_type: A #DnfLockType, e.g. %DNF_LOCK_TYPE_RPMDB
+ * @lock_mode: A #DnfLockMode, e.g. %DNF_LOCK_MODE_PROCESS
+ * @error: A #GError
+ *
+ * Takes a lock of a specified type.
+ * The lock is automatically free'd when the DnfState has been completed.
+ *
+ * You can call dnf_state_take_lock() multiple times with different or
+ * even the same @lock_type value.
+ *
+ * Returns: %FALSE if the lock is fatal, %TRUE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_take_lock(DnfState *state,
+ DnfLockType lock_type,
+ DnfLockMode lock_mode,
+ GError **error) try
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ guint lock_id = 0;
+
+ /* no custom handler */
+ lock_id = dnf_lock_take(priv->lock,
+ lock_type,
+ lock_mode,
+ error);
+ if (lock_id == 0)
+ return FALSE;
+
+ /* add the lock to an array so we can release on completion */
+ g_debug("adding lock %i", lock_id);
+ g_ptr_array_add(priv->lock_ids,
+ GUINT_TO_POINTER(lock_id));
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_state_discrete_to_percent:
+ **/
+static gfloat
+dnf_state_discrete_to_percent(guint discrete, guint steps)
+{
+ /* check we are in range */
+ if (discrete > steps)
+ return 100;
+ if (steps == 0) {
+ g_warning("steps is 0!");
+ return 0;
+ }
+ return((gfloat) ((gdouble) discrete *(100.0 /(gdouble)(steps))));
+}
+
+/**
+ * dnf_state_print_parent_chain:
+ **/
+static void
+dnf_state_print_parent_chain(DnfState *state, guint level)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ if (priv->parent != NULL)
+ dnf_state_print_parent_chain(priv->parent, level + 1);
+ g_print("%i) %s(%i/%i)\n",
+ level, priv->id, priv->current, priv->steps);
+}
+
+/**
+ * dnf_state_get_cancellable:
+ * @state: A #DnfState
+ *
+ * Gets the #GCancellable for this operation
+ *
+ * Returns:(transfer none): The #GCancellable or %NULL
+ *
+ * Since: 0.1.0
+ **/
+GCancellable *
+dnf_state_get_cancellable(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->cancellable;
+}
+
+/**
+ * dnf_state_set_cancellable:
+ * @state: a #DnfState instance.
+ * @cancellable: The #GCancellable which is used to cancel tasks, or %NULL
+ *
+ * Sets the #GCancellable object to use.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_cancellable(DnfState *state, GCancellable *cancellable)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ g_return_if_fail(priv->cancellable == NULL);
+ if (priv->cancellable != NULL)
+ g_clear_object(&priv->cancellable);
+ if (cancellable != NULL)
+ priv->cancellable = static_cast<GCancellable *>(g_object_ref(cancellable));
+}
+
+/**
+ * dnf_state_get_allow_cancel:
+ * @state: A #DnfState
+ *
+ * Gets if the sub-task(or one of it's sub-sub-tasks) is cancellable
+ *
+ * Returns: %TRUE if the translation has a chance of being cancelled
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_get_allow_cancel(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->allow_cancel && priv->allow_cancel_child;
+}
+
+/**
+ * dnf_state_set_allow_cancel:
+ * @state: A #DnfState
+ * @allow_cancel: If this sub-task can be cancelled
+ *
+ * Set is this sub task can be cancelled safely.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_allow_cancel(DnfState *state, gboolean allow_cancel)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ priv->allow_cancel_changed_state = TRUE;
+
+ /* quick optimisation that saves lots of signals */
+ if (priv->allow_cancel == allow_cancel)
+ return;
+ priv->allow_cancel = allow_cancel;
+
+ /* just emit if both this and child is okay */
+ g_signal_emit(state, signals [SIGNAL_ALLOW_CANCEL_CHANGED], 0,
+ priv->allow_cancel && priv->allow_cancel_child);
+}
+
+/**
+ * dnf_state_get_speed:
+ * @state: a #DnfState instance.
+ *
+ * Gets the transaction speed in bytes per second.
+ *
+ * Returns: speed, or 0 for unknown.
+ *
+ * Since: 0.1.0
+ **/
+guint64
+dnf_state_get_speed(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->speed;
+}
+
+/**
+ * dnf_state_set_speed-private:
+ **/
+static void
+dnf_state_set_speed_internal(DnfState *state, guint64 speed)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ if (priv->speed == speed)
+ return;
+ priv->speed = speed;
+ g_object_notify(G_OBJECT(state), "speed");
+}
+
+/**
+ * dnf_state_set_speed:
+ * @state: a #DnfState instance.
+ * @speed: The transaction speed.
+ *
+ * Sets the download or install transaction speed in bytes per second.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_speed(DnfState *state, guint64 speed)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ guint i;
+ guint64 sum = 0;
+ guint sum_cnt = 0;
+
+ /* move the data down one entry */
+ for (i=DNF_STATE_SPEED_SMOOTHING_ITEMS-1; i > 0; i--)
+ priv->speed_data[i] = priv->speed_data[i-1];
+ priv->speed_data[0] = speed;
+
+ /* get the average */
+ for (i = 0; i < DNF_STATE_SPEED_SMOOTHING_ITEMS; i++) {
+ if (priv->speed_data[i] > 0) {
+ sum += priv->speed_data[i];
+ sum_cnt++;
+ }
+ }
+ if (sum_cnt > 0)
+ sum /= sum_cnt;
+
+ dnf_state_set_speed_internal(state, sum);
+}
+
+/**
+ * dnf_state_release_locks:
+ * @state: a #DnfState instance.
+ *
+ * Releases all locks used in the state.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_release_locks(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ guint i;
+ guint lock_id;
+
+ /* release children first */
+ if (priv->child != NULL)
+ dnf_state_release_locks(priv->child);
+
+ /* release each one */
+ for (i = 0; i < priv->lock_ids->len; i++) {
+ lock_id = GPOINTER_TO_UINT(g_ptr_array_index(priv->lock_ids, i));
+ g_debug("releasing lock %i", lock_id);
+ if (!dnf_lock_release(priv->lock, lock_id, NULL))
+ return FALSE;
+ }
+ g_ptr_array_set_size(priv->lock_ids, 0);
+ return TRUE;
+}
+
+/**
+ * dnf_state_set_percentage:
+ * @state: a #DnfState instance.
+ * @percentage: Percentage value between 0% and 100%
+ *
+ * Set a percentage manually.
+ * NOTE: this must be above what was previously set, or it will be rejected.
+ *
+ * Returns: %TRUE if the signal was propagated, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_set_percentage(DnfState *state, guint percentage)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ /* do we care */
+ if (!priv->report_progress)
+ return TRUE;
+
+ /* is it the same */
+ if (percentage == priv->last_percentage)
+ return FALSE;
+
+ /* is it invalid */
+ if (percentage > 100) {
+ dnf_state_print_parent_chain(state, 0);
+ g_warning("percentage %i%% is invalid on %p!",
+ percentage, state);
+ return FALSE;
+ }
+
+ /* is it less */
+ if (percentage < priv->last_percentage) {
+ if (priv->enable_profile) {
+ dnf_state_print_parent_chain(state, 0);
+ g_warning("percentage should not go down from %i to %i on %p!",
+ priv->last_percentage, percentage, state);
+ }
+ return FALSE;
+ }
+
+ /* we're done, so we're not preventing cancellation anymore */
+ if (percentage == 100 && !priv->allow_cancel) {
+ g_debug("done, so allow cancel 1 for %p", state);
+ dnf_state_set_allow_cancel(state, TRUE);
+ }
+
+ /* automatically cancel any action */
+ if (percentage == 100 && priv->action != DNF_STATE_ACTION_UNKNOWN)
+ dnf_state_action_stop(state);
+
+ /* speed no longer valid */
+ if (percentage == 100)
+ dnf_state_set_speed_internal(state, 0);
+
+ /* release locks? */
+ if (percentage == 100) {
+ if (!dnf_state_release_locks(state))
+ return FALSE;
+ }
+
+ /* save */
+ priv->last_percentage = percentage;
+
+ /* emit */
+ g_signal_emit(state, signals [SIGNAL_PERCENTAGE_CHANGED], 0, percentage);
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * dnf_state_get_percentage:
+ * @state: a #DnfState instance.
+ *
+ * Get the percentage state.
+ *
+ * Returns: The percentage value, or %G_MAXUINT for error
+ *
+ * Since: 0.1.0
+ **/
+guint
+dnf_state_get_percentage(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->last_percentage;
+}
+
+/**
+ * dnf_state_action_start:
+ * @state: a #DnfState instance.
+ * @action: An action, e.g. %DNF_STATE_ACTION_DECOMPRESSING
+ * @action_hint: A hint on what the action is doing, e.g. "/var/cache/yum/i386/15/koji/primary.sqlite"
+ *
+ * Sets the action which is being performed. This is emitted up the chain
+ * to any parent %DnfState objects, using the action-changed signal.
+ *
+ * If a %DnfState reaches 100% then it is automatically stopped with a
+ * call to dnf_state_action_stop().
+ *
+ * It is allowed to call dnf_state_action_start() more than once for a
+ * given %DnfState instance.
+ *
+ * Returns: %TRUE if the signal was propagated, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_action_start(DnfState *state, DnfStateAction action, const gchar *action_hint)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ /* ignore this */
+ if (action == DNF_STATE_ACTION_UNKNOWN) {
+ g_warning("cannot set action DNF_STATE_ACTION_UNKNOWN");
+ return FALSE;
+ }
+
+ /* is different? */
+ if (priv->action == action &&
+ g_strcmp0(action_hint, priv->action_hint) == 0)
+ return FALSE;
+
+ /* remember for stop */
+ priv->last_action = priv->action;
+
+ /* save hint */
+ g_free(priv->action_hint);
+ priv->action_hint = g_strdup(action_hint);
+
+ /* save */
+ priv->action = action;
+
+ /* just emit */
+ g_signal_emit(state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
+ return TRUE;
+}
+
+/**
+ * dnf_state_set_package_progress:
+ * @state: a #DnfState instance.
+ * @dnf_package_get_id: A package_id
+ * @action: A #DnfStateAction
+ * @percentage: A percentage
+ *
+ * Sets any package progress.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_state_set_package_progress(DnfState *state,
+ const gchar *dnf_package_get_id,
+ DnfStateAction action,
+ guint percentage)
+{
+ g_return_if_fail(dnf_package_get_id != NULL);
+ g_return_if_fail(action != DNF_STATE_ACTION_UNKNOWN);
+ g_return_if_fail(percentage <= 100);
+
+ /* just emit */
+ g_signal_emit(state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
+ dnf_package_get_id, action, percentage);
+}
+
+/**
+ * dnf_state_action_stop:
+ * @state: A #DnfState
+ *
+ * Returns the DnfState to it's previous value.
+ * It is not expected you will ever need to use this function.
+ *
+ * Returns: %TRUE if the signal was propagated, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_action_stop(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ /* nothing ever set */
+ if (priv->action == DNF_STATE_ACTION_UNKNOWN) {
+ g_debug("cannot unset action DNF_STATE_ACTION_UNKNOWN");
+ return FALSE;
+ }
+
+ /* pop and reset */
+ priv->action = priv->last_action;
+ priv->last_action = DNF_STATE_ACTION_UNKNOWN;
+ if (priv->action_hint != NULL) {
+ g_free(priv->action_hint);
+ priv->action_hint = NULL;
+ }
+
+ /* just emit */
+ g_signal_emit(state, signals [SIGNAL_ACTION_CHANGED], 0, priv->action, NULL);
+ return TRUE;
+}
+
+/**
+ * dnf_state_get_action_hint:
+ * @state: a #DnfState instance.
+ *
+ * Gets the action hint, which may be useful to the users.
+ *
+ * Returns: An a ction hint, e.g. "/var/cache/yum/i386/15/koji/primary.sqlite"
+ *
+ * Since: 0.1.0
+ **/
+const gchar *
+dnf_state_get_action_hint(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->action_hint;
+}
+
+/**
+ * dnf_state_get_action:
+ * @state: a #DnfState instance.
+ *
+ * Gets the last set action value.
+ *
+ * Returns: An action, e.g. %DNF_STATE_ACTION_DECOMPRESSING
+ *
+ * Since: 0.1.0
+ **/
+DnfStateAction
+dnf_state_get_action(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ return priv->action;
+}
+
+/**
+ * dnf_state_child_percentage_changed_cb:
+ **/
+static void
+dnf_state_child_percentage_changed_cb(DnfState *child, guint percentage, DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ gfloat offset;
+ gfloat range;
+ gfloat extra;
+ guint parent_percentage;
+
+ /* propagate up the stack if DnfState has only one step */
+ if (priv->steps == 1) {
+ dnf_state_set_percentage(state, percentage);
+ return;
+ }
+
+ /* did we call done on a state that did not have a size set? */
+ if (priv->steps == 0)
+ return;
+
+ /* already at >= 100% */
+ if (priv->current >= priv->steps) {
+ g_warning("already at %i/%i steps on %p", priv->current, priv->steps, state);
+ return;
+ }
+
+ /* we have to deal with non-linear steps */
+ if (priv->step_data != NULL) {
+ /* we don't store zero */
+ if (priv->current == 0) {
+ parent_percentage = percentage * priv->step_data[priv->current] / 100;
+ } else {
+ /* bilinearly interpolate for speed */
+ parent_percentage =(((100 - percentage) * priv->step_data[priv->current-1]) +
+ (percentage * priv->step_data[priv->current])) / 100;
+ }
+ goto out;
+ }
+
+ /* get the offset */
+ offset = dnf_state_discrete_to_percent(priv->current, priv->steps);
+
+ /* get the range between the parent step and the next parent step */
+ range = dnf_state_discrete_to_percent(priv->current+1, priv->steps) - offset;
+ if (range < 0.01) {
+ g_warning("range=%f(from %i to %i), should be impossible", range, priv->current+1, priv->steps);
+ return;
+ }
+
+ /* restore the pre-child action */
+ if (percentage == 100)
+ priv->last_action = priv->child_action;
+
+ /* get the extra contributed by the child */
+ extra =((gfloat) percentage / 100.0f) * range;
+
+ /* emit from the parent */
+ parent_percentage =(guint)(offset + extra);
+out:
+ dnf_state_set_percentage(state, parent_percentage);
+}
+
+/**
+ * dnf_state_child_allow_cancel_changed_cb:
+ **/
+static void
+dnf_state_child_allow_cancel_changed_cb(DnfState *child, gboolean allow_cancel, DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ /* save */
+ priv->allow_cancel_child = allow_cancel;
+
+ /* just emit if both this and child is okay */
+ g_signal_emit(state, signals [SIGNAL_ALLOW_CANCEL_CHANGED], 0,
+ priv->allow_cancel && priv->allow_cancel_child);
+}
+
+/**
+ * dnf_state_child_action_changed_cb:
+ **/
+static void
+dnf_state_child_action_changed_cb(DnfState *child,
+ DnfStateAction action,
+ const gchar *action_hint,
+ DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ /* save */
+ priv->action = action;
+
+ /* just emit */
+ g_signal_emit(state, signals [SIGNAL_ACTION_CHANGED], 0, action, action_hint);
+}
+
+/**
+ * dnf_state_child_package_progress_changed_cb:
+ **/
+static void
+dnf_state_child_package_progress_changed_cb(DnfState *child,
+ const gchar *dnf_package_get_id,
+ DnfStateAction action,
+ guint progress,
+ DnfState *state)
+{
+ /* just emit */
+ g_signal_emit(state, signals [SIGNAL_PACKAGE_PROGRESS_CHANGED], 0,
+ dnf_package_get_id, action, progress);
+}
+
+/**
+ * dnf_state_reset:
+ * @state: a #DnfState instance.
+ *
+ * Resets the #DnfState object to unset
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_reset(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ g_return_val_if_fail(DNF_IS_STATE(state), FALSE);
+
+ /* do we care */
+ if (!priv->report_progress)
+ return TRUE;
+
+ /* reset values */
+ priv->steps = 0;
+ priv->current = 0;
+ priv->last_percentage = 0;
+
+ /* only use the timer if profiling; it's expensive */
+ if (priv->enable_profile)
+ g_timer_start(priv->timer);
+
+ /* disconnect client */
+ if (priv->percentage_child_id != 0) {
+ g_signal_handler_disconnect(priv->child, priv->percentage_child_id);
+ priv->percentage_child_id = 0;
+ }
+ if (priv->allow_cancel_child_id != 0) {
+ g_signal_handler_disconnect(priv->child, priv->allow_cancel_child_id);
+ priv->allow_cancel_child_id = 0;
+ }
+ if (priv->action_child_id != 0) {
+ g_signal_handler_disconnect(priv->child, priv->action_child_id);
+ priv->action_child_id = 0;
+ }
+ if (priv->package_progress_child_id != 0) {
+ g_signal_handler_disconnect(priv->child, priv->package_progress_child_id);
+ priv->package_progress_child_id = 0;
+ }
+ if (priv->notify_speed_child_id != 0) {
+ g_signal_handler_disconnect(priv->child, priv->notify_speed_child_id);
+ priv->notify_speed_child_id = 0;
+ }
+
+ /* unref child */
+ if (priv->child != NULL) {
+ g_object_unref(priv->child);
+ priv->child = NULL;
+ }
+
+ /* no more locks */
+ dnf_state_release_locks(state);
+
+ /* no more step data */
+ g_free(priv->step_data);
+ g_free(priv->step_profile);
+ priv->step_data = NULL;
+ priv->step_profile = NULL;
+ return TRUE;
+}
+
+/**
+ * dnf_state_child_notify_speed_cb:
+ **/
+static void
+dnf_state_child_notify_speed_cb(DnfState *child,
+ GParamSpec *pspec,
+ DnfState *state)
+{
+ dnf_state_set_speed_internal(state,
+ dnf_state_get_speed(child));
+}
+
+/**
+ * dnf_state_get_child:
+ * @state: a #DnfState instance.
+ *
+ * Monitor a child state and proxy back up to the parent state.
+ * You should not g_object_unref() this object, it is owned by the parent.
+ *
+ * Returns:(transfer none): A new %DnfState or %NULL for failure
+ *
+ * Since: 0.1.0
+ **/
+DnfState *
+dnf_state_get_child(DnfState *state)
+{
+ DnfState *child = NULL;
+ DnfStatePrivate *child_priv;
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ g_return_val_if_fail(DNF_IS_STATE(state), NULL);
+
+ /* do we care */
+ if (!priv->report_progress)
+ return state;
+
+ /* already set child */
+ if (priv->child != NULL) {
+ g_signal_handler_disconnect(priv->child,
+ priv->percentage_child_id);
+ g_signal_handler_disconnect(priv->child,
+ priv->allow_cancel_child_id);
+ g_signal_handler_disconnect(priv->child,
+ priv->action_child_id);
+ g_signal_handler_disconnect(priv->child,
+ priv->package_progress_child_id);
+ g_signal_handler_disconnect(priv->child,
+ priv->notify_speed_child_id);
+ g_object_unref(priv->child);
+ }
+
+ /* connect up signals */
+ child = dnf_state_new();
+ child_priv = GET_PRIVATE(child);
+ child_priv->parent = state; /* do not ref! */
+ priv->child = child;
+ priv->percentage_child_id =
+ g_signal_connect(child, "percentage-changed",
+ G_CALLBACK(dnf_state_child_percentage_changed_cb),
+ state);
+ priv->allow_cancel_child_id =
+ g_signal_connect(child, "allow-cancel-changed",
+ G_CALLBACK(dnf_state_child_allow_cancel_changed_cb),
+ state);
+ priv->action_child_id =
+ g_signal_connect(child, "action-changed",
+ G_CALLBACK(dnf_state_child_action_changed_cb),
+ state);
+ priv->package_progress_child_id =
+ g_signal_connect(child, "package-progress-changed",
+ G_CALLBACK(dnf_state_child_package_progress_changed_cb),
+ state);
+ priv->notify_speed_child_id =
+ g_signal_connect(child, "notify::speed",
+ G_CALLBACK(dnf_state_child_notify_speed_cb),
+ state);
+
+ /* reset child */
+ child_priv->current = 0;
+ child_priv->last_percentage = 0;
+
+ /* save so we can recover after child has done */
+ child_priv->action = priv->action;
+ priv->child_action = priv->action;
+
+ /* set cancellable, creating if required */
+ if (priv->cancellable == NULL)
+ priv->cancellable = g_cancellable_new();
+ dnf_state_set_cancellable(child, priv->cancellable);
+
+ /* set the profile state */
+ dnf_state_set_enable_profile(child, priv->enable_profile);
+ return child;
+}
+
+/**
+ * dnf_state_set_number_steps_real:
+ * @state: a #DnfState instance.
+ * @steps: The number of sub-tasks in this transaction, can be 0
+ * @strloc: Code position identifier.
+ *
+ * Sets the number of sub-tasks, i.e. how many times the dnf_state_done()
+ * function will be called in the loop.
+ *
+ * The function will immediately return with TRUE when the number of steps is 0
+ * or if dnf_state_set_report_progress(FALSE) was previously called.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_set_number_steps_real(DnfState *state, guint steps, const gchar *strloc)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ g_return_val_if_fail(state != NULL, FALSE);
+
+ /* nothing to do for 0 steps */
+ if (steps == 0)
+ return TRUE;
+
+ /* do we care */
+ if (!priv->report_progress)
+ return TRUE;
+
+ /* did we call done on a state that did not have a size set? */
+ if (priv->steps != 0) {
+ g_warning("steps already set to %i, can't set %i! [%s]",
+ priv->steps, steps, strloc);
+ dnf_state_print_parent_chain(state, 0);
+ return FALSE;
+ }
+
+ /* set id */
+ g_free(priv->id);
+ priv->id = g_strdup_printf("%s", strloc);
+
+ /* only use the timer if profiling; it's expensive */
+ if (priv->enable_profile)
+ g_timer_start(priv->timer);
+
+ /* set steps */
+ priv->steps = steps;
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * dnf_state_set_steps_real:
+ * @state: a #DnfState instance.
+ * @error: A #GError, or %NULL
+ * @strloc: the code location
+ * @value: A step weighting variable argument array
+ * @...: -1 terminated step values
+ *
+ * This sets the step weighting, which you will want to do if one action
+ * will take a bigger chunk of time than another.
+ *
+ * All the values must add up to 100, and the list must end with -1.
+ * Do not use this function directly, instead use the dnf_state_set_steps() macro.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_set_steps_real(DnfState *state, GError **error, const gchar *strloc, gint value, ...) try
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ va_list args;
+ guint i;
+ gint value_temp;
+ guint total;
+
+ g_return_val_if_fail(state != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* do we care */
+ if (!priv->report_progress)
+ return TRUE;
+
+ /* we must set at least one thing */
+ total = value;
+
+ /* process the valist */
+ va_start(args, value);
+ for (i = 0;; i++) {
+ value_temp = va_arg(args, gint);
+ if (value_temp == -1)
+ break;
+ total +=(guint) value_temp;
+ }
+ va_end(args);
+
+ /* does not sum to 100% */
+ if (total != 100) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("percentage not 100: %i"),
+ total);
+ return FALSE;
+ }
+
+ /* set step number */
+ if (!dnf_state_set_number_steps_real(state, i+1, strloc)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to set number steps: %i"),
+ i+1);
+ return FALSE;
+ }
+
+ /* save this data */
+ total = value;
+ priv->step_data = g_new0(guint, i+2);
+ priv->step_profile = g_new0(gdouble, i+2);
+ priv->step_data[0] = total;
+ va_start(args, value);
+ for (i = 0;; i++) {
+ value_temp = va_arg(args, gint);
+ if (value_temp == -1)
+ break;
+
+ /* we pre-add the data to make access simpler */
+ total +=(guint) value_temp;
+ priv->step_data[i+1] = total;
+ }
+ va_end(args);
+
+ /* success */
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_state_show_profile:
+ **/
+static void
+dnf_state_show_profile(DnfState *state)
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ gdouble division;
+ gdouble total_time = 0.0f;
+ GString *result;
+ guint i;
+ guint uncumalitive = 0;
+
+ /* get the total time */
+ for (i = 0; i < priv->steps; i++)
+ total_time += priv->step_profile[i];
+ if (total_time < 0.01)
+ return;
+
+ /* get the total time so we can work out the divisor */
+ result = g_string_new("Raw timing data was { ");
+ for (i = 0; i < priv->steps; i++) {
+ g_string_append_printf(result, "%.3f, ",
+ priv->step_profile[i]);
+ }
+ if (priv->steps > 0)
+ g_string_set_size(result, result->len - 2);
+ g_string_append(result, " }\n");
+
+ /* what we set */
+ g_string_append(result, "steps were set as [ ");
+ for (i = 0; i < priv->steps; i++) {
+ g_string_append_printf(result, "%i, ",
+ priv->step_data[i] - uncumalitive);
+ uncumalitive = priv->step_data[i];
+ }
+
+ /* what we _should_ have set */
+ g_string_append_printf(result, "-1 ] but should have been: [ ");
+ division = total_time / 100.0f;
+ for (i = 0; i < priv->steps; i++) {
+ g_string_append_printf(result, "%.0f, ",
+ priv->step_profile[i] / division);
+ }
+ g_string_append(result, "-1 ]");
+ g_printerr("\n\n%s at %s\n\n", result->str, priv->id);
+ g_string_free(result, TRUE);
+}
+
+/**
+ * dnf_state_check:
+ * @state: a #DnfState instance.
+ * @error: A #GError or %NULL
+ *
+ * Do any checks to see if the task has been cancelled.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_check(DnfState *state, GError **error) try
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ g_return_val_if_fail(state != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* are we cancelled */
+ if (g_cancellable_is_cancelled(priv->cancellable)) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_CANCELLED,
+ _("cancelled by user action"));
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_state_done_real:
+ * @state: a #DnfState instance.
+ * @error: A #GError or %NULL
+ * @strloc: Code position identifier.
+ *
+ * Called when the current sub-task has finished.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_done_real(DnfState *state, GError **error, const gchar *strloc) try
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+ gdouble elapsed;
+ gfloat percentage;
+
+ g_return_val_if_fail(state != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* check */
+ if (!dnf_state_check(state, error))
+ return FALSE;
+
+ /* do we care */
+ if (!priv->report_progress)
+ return TRUE;
+
+ /* did we call done on a state that did not have a size set? */
+ if (priv->steps == 0) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("done on a state %1$p that did not have a size set! [%2$s]"),
+ state, strloc);
+ dnf_state_print_parent_chain(state, 0);
+ return FALSE;
+ }
+
+ /* check the interval was too big in allow_cancel false mode */
+ if (priv->enable_profile) {
+ elapsed = g_timer_elapsed(priv->timer, NULL);
+ if (!priv->allow_cancel_changed_state && priv->current > 0) {
+ if (elapsed > 0.1f) {
+ g_warning("%.1fms between dnf_state_done() and no dnf_state_set_allow_cancel()", elapsed * 1000);
+ dnf_state_print_parent_chain(state, 0);
+ }
+ }
+
+ /* save the duration in the array */
+ if (priv->step_profile != NULL)
+ priv->step_profile[priv->current] = elapsed;
+ g_timer_start(priv->timer);
+ }
+
+ /* is already at 100%? */
+ if (priv->current >= priv->steps) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("already at 100%% state [%s]"), strloc);
+ dnf_state_print_parent_chain(state, 0);
+ return FALSE;
+ }
+
+ /* is child not at 100%? */
+ if (priv->child != NULL) {
+ DnfStatePrivate *child_priv = GET_PRIVATE(priv->child);
+ if (child_priv->current != child_priv->steps) {
+ g_print("child is at %i/%i steps and parent done [%s]\n",
+ child_priv->current, child_priv->steps, strloc);
+ dnf_state_print_parent_chain(priv->child, 0);
+ /* do not abort, as we want to clean this up */
+ }
+ }
+
+ /* we just checked for cancel, so it's not true to say we're blocking */
+ dnf_state_set_allow_cancel(state, TRUE);
+
+ /* another */
+ priv->current++;
+
+ /* find new percentage */
+ if (priv->step_data == NULL) {
+ percentage = dnf_state_discrete_to_percent(priv->current,
+ priv->steps);
+ } else {
+ /* this is cumalative, for speedy access */
+ percentage = priv->step_data[priv->current - 1];
+ }
+ dnf_state_set_percentage(state,(guint) percentage);
+
+ /* show any profiling stats */
+ if (priv->enable_profile &&
+ priv->current == priv->steps &&
+ priv->step_profile != NULL) {
+ dnf_state_show_profile(state);
+ }
+
+ /* reset child if it exists */
+ if (priv->child != NULL)
+ dnf_state_reset(priv->child);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_state_finished_real:
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ * @strloc: Code position identifier.
+ *
+ * Called when the current sub-task has finished.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_state_finished_real(DnfState *state, GError **error, const gchar *strloc) try
+{
+ DnfStatePrivate *priv = GET_PRIVATE(state);
+
+ g_return_val_if_fail(state != NULL, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ /* check */
+ if (!dnf_state_check(state, error))
+ return FALSE;
+
+ /* is already at 100%? */
+ if (priv->current == priv->steps)
+ return TRUE;
+
+ /* all done */
+ priv->current = priv->steps;
+
+ /* set new percentage */
+ dnf_state_set_percentage(state, 100);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_state_new:
+ *
+ * Creates a new #DnfState.
+ *
+ * Returns:(transfer full): a #DnfState
+ *
+ * Since: 0.1.0
+ **/
+DnfState *
+dnf_state_new(void)
+{
+ return DNF_STATE(g_object_new(DNF_TYPE_STATE, NULL));
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2009-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_STATE_H
+#define __DNF_STATE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "dnf-types.h"
+#include "dnf-lock.h"
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_STATE (dnf_state_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfState, dnf_state, DNF, STATE, GObject)
+
+/**
+ * DnfStateAction:
+ * @DNF_STATE_ACTION_UNKNOWN: Unknown status
+ * @DNF_STATE_ACTION_DOWNLOAD_PACKAGES: Downloading packages
+ * @DNF_STATE_ACTION_DOWNLOAD_METADATA: Downloading metadata
+ * @DNF_STATE_ACTION_LOADING_CACHE: Loading cache
+ * @DNF_STATE_ACTION_TEST_COMMIT: Testing transaction
+ * @DNF_STATE_ACTION_REQUEST: Requesting data
+ * @DNF_STATE_ACTION_REMOVE: Removing packages
+ * @DNF_STATE_ACTION_INSTALL: Installing packages
+ * @DNF_STATE_ACTION_UPDATE: Updating packages
+ * @DNF_STATE_ACTION_CLEANUP: Cleaning packages
+ * @DNF_STATE_ACTION_OBSOLETE: Obsoleting packages
+ * @DNF_STATE_ACTION_REINSTALL: Reinstall packages
+ * @DNF_STATE_ACTION_DOWNGRADE: Downgrading packages
+ * @DNF_STATE_ACTION_QUERY: Querying for results
+ *
+ * The action enum code.
+ **/
+typedef enum {
+ DNF_STATE_ACTION_UNKNOWN = 0, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_DOWNLOAD_PACKAGES = 8, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_DOWNLOAD_METADATA = 20, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_LOADING_CACHE = 27, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_TEST_COMMIT = 15, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_REQUEST = 17, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_REMOVE = 6, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_INSTALL = 9, /* Since: 0.1.0 */
+ DNF_STATE_ACTION_UPDATE = 10, /* Since: 0.1.2 */
+ DNF_STATE_ACTION_CLEANUP = 11, /* Since: 0.1.2 */
+ DNF_STATE_ACTION_OBSOLETE = 12, /* Since: 0.1.2 */
+ DNF_STATE_ACTION_REINSTALL = 13, /* Since: 0.1.6 */
+ DNF_STATE_ACTION_DOWNGRADE = 14, /* Since: 0.1.6 */
+ DNF_STATE_ACTION_QUERY = 4, /* Since: 0.1.2 */
+ /*< private >*/
+ DNF_STATE_ACTION_LAST
+} DnfStateAction;
+
+struct _DnfStateClass
+{
+ GObjectClass parent_class;
+ void (* percentage_changed) (DnfState *state,
+ guint value);
+ void (* allow_cancel_changed) (DnfState *state,
+ gboolean allow_cancel);
+ void (* action_changed) (DnfState *state,
+ DnfStateAction action,
+ const gchar *action_hint);
+ void (* package_progress_changed) (DnfState *state,
+ const gchar *dnf_package_get_id,
+ DnfStateAction action,
+ guint percentage);
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+#define dnf_state_done(state, error) dnf_state_done_real(state, error, G_STRLOC)
+#define dnf_state_finished(state, error) dnf_state_finished_real(state, error, G_STRLOC)
+#define dnf_state_set_number_steps(state, steps) dnf_state_set_number_steps_real(state, steps, G_STRLOC)
+#define dnf_state_set_steps(state, error, value, args...) dnf_state_set_steps_real(state, error, G_STRLOC, value, ## args)
+
+typedef gboolean (*DnfStateErrorHandlerCb) (const GError *error,
+ gpointer user_data);
+
+DnfState *dnf_state_new (void);
+
+/* getters */
+guint dnf_state_get_percentage (DnfState *state);
+DnfStateAction dnf_state_get_action (DnfState *state);
+const gchar *dnf_state_get_action_hint (DnfState *state);
+GCancellable *dnf_state_get_cancellable (DnfState *state);
+gboolean dnf_state_get_allow_cancel (DnfState *state);
+guint64 dnf_state_get_speed (DnfState *state);
+
+/* setters */
+void dnf_state_set_cancellable (DnfState *state,
+ GCancellable *cancellable);
+void dnf_state_set_allow_cancel (DnfState *state,
+ gboolean allow_cancel);
+void dnf_state_set_speed (DnfState *state,
+ guint64 speed);
+void dnf_state_set_report_progress (DnfState *state,
+ gboolean report_progress);
+gboolean dnf_state_set_number_steps_real (DnfState *state,
+ guint steps,
+ const gchar *strloc);
+gboolean dnf_state_set_steps_real (DnfState *state,
+ GError **error,
+ const gchar *strloc,
+ gint value, ...);
+gboolean dnf_state_set_percentage (DnfState *state,
+ guint percentage);
+void dnf_state_set_package_progress (DnfState *state,
+ const gchar *dnf_package_get_id,
+ DnfStateAction action,
+ guint percentage);
+
+/* object methods */
+DnfState *dnf_state_get_child (DnfState *state);
+gboolean dnf_state_action_start (DnfState *state,
+ DnfStateAction action,
+ const gchar *action_hint);
+gboolean dnf_state_action_stop (DnfState *state);
+gboolean dnf_state_check (DnfState *state,
+ GError **error)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean dnf_state_done_real (DnfState *state,
+ GError **error,
+ const gchar *strloc)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean dnf_state_finished_real (DnfState *state,
+ GError **error,
+ const gchar *strloc)
+ G_GNUC_WARN_UNUSED_RESULT;
+gboolean dnf_state_reset (DnfState *state);
+void dnf_state_set_enable_profile (DnfState *state,
+ gboolean enable_profile);
+#ifndef __GI_SCANNER__
+gboolean dnf_state_take_lock (DnfState *state,
+ DnfLockType lock_type,
+ DnfLockMode lock_mode,
+ GError **error);
+#endif
+gboolean dnf_state_release_locks (DnfState *state);
+
+G_END_DECLS
+
+#endif /* __DNF_STATE_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-transaction
+ * @short_description: High level interface to librpm.
+ * @include: libdnf.h
+ * @stability: Stable
+ *
+ * This object represents an RPM transaction.
+ */
+
+#include <rpm/rpmdb.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmts.h>
+
+#include "catch-error.hpp"
+#include "log.hpp"
+#include "tinyformat/tinyformat.hpp"
+#include "dnf-context.hpp"
+#include "dnf-goal.h"
+#include "dnf-keyring.h"
+#include "dnf-package.h"
+#include "dnf-rpmts-private.hpp"
+#include "dnf-sack.h"
+#include "dnf-sack-private.hpp"
+#include "dnf-transaction.h"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+#include "hy-query.h"
+#include "hy-util-private.hpp"
+#include "plugin/plugin-private.hpp"
+
+#include "module/ModulePackageContainer.hpp"
+#include "transaction/Swdb.hpp"
+#include "transaction/Transformer.hpp"
+#include "utils/bgettext/bgettext-lib.h"
+#include "utils/utils.hpp"
+
+typedef enum {
+ DNF_TRANSACTION_STEP_STARTED,
+ DNF_TRANSACTION_STEP_PREPARING,
+ DNF_TRANSACTION_STEP_WRITING,
+ DNF_TRANSACTION_STEP_IGNORE
+} DnfTransactionStep;
+
+typedef struct {
+ rpmKeyring keyring;
+ rpmts ts;
+ DnfContext *context; /* weak reference */
+ GPtrArray *repos;
+ guint uid;
+
+ /* previously in the helper */
+ DnfState *state;
+ DnfState *child;
+ FD_t fd;
+ DnfTransactionStep step;
+ GTimer *timer;
+ guint last_progress;
+ GPtrArray *remove;
+ GPtrArray *remove_helper;
+ GPtrArray *install;
+ GPtrArray *pkgs_to_download;
+ GHashTable *erased_by_package_hash;
+ guint64 flags;
+ gboolean dont_solve_goal;
+ libdnf::Swdb *swdb;
+} DnfTransactionPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfTransaction, dnf_transaction, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) \
+ (static_cast< DnfTransactionPrivate * >(dnf_transaction_get_instance_private(o)))
+
+/**
+* @brief Information about running transaction
+*
+* The structure is passed to pluginHook() as hookData, when id of hook
+* is PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION or PLUGIN_HOOK_ID_CONTEXT_TRANSACTION.
+*/
+struct PluginHookContextTransactionData : public libdnf::PluginHookData {
+ PluginHookContextTransactionData(PluginHookId hookId, DnfTransaction * transaction,
+ HyGoal goal, DnfState * state)
+ : PluginHookData(hookId), transaction(transaction), goal(goal), state(state) {}
+
+ DnfTransaction * transaction;
+ HyGoal goal;
+ DnfState * state;
+};
+
+/**
+ * dnf_transaction_finalize:
+ **/
+static void
+dnf_transaction_finalize(GObject *object)
+{
+ DnfTransaction *transaction = DNF_TRANSACTION(object);
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+
+ g_ptr_array_unref(priv->pkgs_to_download);
+ g_timer_destroy(priv->timer);
+ rpmKeyringFree(priv->keyring);
+ rpmtsFree(priv->ts);
+
+ if (priv->swdb != NULL)
+ delete priv->swdb;
+ if (priv->repos != NULL)
+ g_ptr_array_unref(priv->repos);
+ if (priv->install != NULL)
+ g_ptr_array_unref(priv->install);
+ if (priv->remove != NULL)
+ g_ptr_array_unref(priv->remove);
+ if (priv->remove_helper != NULL)
+ g_ptr_array_unref(priv->remove_helper);
+ if (priv->erased_by_package_hash != NULL)
+ g_hash_table_unref(priv->erased_by_package_hash);
+ if (priv->context != NULL)
+ g_object_remove_weak_pointer(G_OBJECT(priv->context), (void **)&priv->context);
+
+ G_OBJECT_CLASS(dnf_transaction_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_transaction_init:
+ **/
+static void
+dnf_transaction_init(DnfTransaction *transaction)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ priv->timer = g_timer_new();
+ priv->pkgs_to_download = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+}
+
+/**
+ * dnf_transaction_class_init:
+ **/
+static void
+dnf_transaction_class_init(DnfTransactionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_transaction_finalize;
+}
+
+/**
+ * dnf_transaction_get_flags:
+ * @transaction: a #DnfTransaction instance.
+ *
+ * Gets the transaction flags.
+ *
+ * Returns: the transaction flags used for this transaction
+ *
+ * Since: 0.1.0
+ **/
+guint64
+dnf_transaction_get_flags(DnfTransaction *transaction)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ return priv->flags;
+}
+
+/**
+ * dnf_transaction_get_remote_pkgs:
+ * @transaction: a #DnfTransaction instance.
+ *
+ * Gets the packages that will be downloaded in dnf_transaction_download().
+ *
+ * The dnf_transaction_depsolve() function must have been called before this
+ * function will return sensible results.
+ *
+ * Returns:(transfer none): the list of packages
+ *
+ * Since: 0.1.0
+ **/
+GPtrArray *
+dnf_transaction_get_remote_pkgs(DnfTransaction *transaction)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ return priv->pkgs_to_download;
+}
+
+DnfDb *
+dnf_transaction_get_db(DnfTransaction *transaction)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ return priv->swdb;
+}
+
+/**
+ * dnf_transaction_set_repos:
+ * @transaction: a #DnfTransaction instance.
+ * @repos: the repos to use with the transaction
+ *
+ * Sets the list of repos.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_transaction_set_repos(DnfTransaction *transaction, GPtrArray *repos)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ if (priv->repos != NULL)
+ g_ptr_array_unref(priv->repos);
+ priv->repos = g_ptr_array_ref(repos);
+}
+
+/**
+ * dnf_transaction_set_uid:
+ * @transaction: a #DnfTransaction instance.
+ * @uid: the uid
+ *
+ * Sets the user ID for the person who started this transaction.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_transaction_set_uid(DnfTransaction *transaction, guint uid)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ priv->uid = uid;
+}
+
+/**
+ * dnf_transaction_set_flags:
+ * @transaction: a #DnfTransaction instance.
+ * @flags: the flags, e.g. %DNF_TRANSACTION_FLAG_ONLY_TRUSTED
+ *
+ * Sets the flags used for this transaction.
+ *
+ * Since: 0.1.0
+ **/
+void
+dnf_transaction_set_flags(DnfTransaction *transaction, guint64 flags)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ priv->flags = flags;
+}
+
+/**
+ * dnf_transaction_set_dont_solve_goal:
+ * @transaction: a #DnfTransaction instance.
+ * @dont_solve_goal: disable/enable calling dnf_goal_depsolve
+ *
+ * Enable/disable calling of dnf_goal_depsolve() in the dnf_transaction_depsolve().
+ *
+ * This function fixes the API problem. The dnf_transaction_depsolve() was allways calling
+ * dnf_goal_depsolve() with hardcoded DnfGoalActions = DNF_ALLOW_UNINSTALL. So, solution
+ * prepared by user was allways replaced.
+ * Default behaviour of existing functions was not changed to be sure of non breaking
+ * of existing API users.
+ *
+ * Since: 0.42.0
+ **/
+void
+dnf_transaction_set_dont_solve_goal(DnfTransaction *transaction, gboolean dont_solve_goal)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ priv->dont_solve_goal = dont_solve_goal;
+}
+
+/**
+ * dnf_transaction_ensure_repo:
+ * @transaction: a #DnfTransaction instance.
+ * @pkg: A #DnfPackage
+ * @error: A #GError or %NULL
+ *
+ * Ensures the #DnfRepo is set on the #DnfPackage *if not already set.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ */
+gboolean
+dnf_transaction_ensure_repo(DnfTransaction *transaction, DnfPackage *pkg, GError **error) try
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ guint i;
+
+ /* not set yet */
+ if (priv->repos == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Sources not set when trying to ensure package %s"),
+ dnf_package_get_name(pkg));
+ return FALSE;
+ }
+
+ /* this is a local file */
+ if (g_strcmp0(dnf_package_get_reponame(pkg), HY_CMDLINE_REPO_NAME) == 0) {
+ dnf_package_set_filename(pkg, dnf_package_get_location(pkg));
+ return TRUE;
+ }
+
+ /* get repo */
+ if (dnf_package_installed(pkg))
+ return TRUE;
+ for (i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast< DnfRepo * >(g_ptr_array_index(priv->repos, i));
+ if (g_strcmp0(dnf_package_get_reponame(pkg), dnf_repo_get_id(repo)) == 0) {
+ dnf_package_set_repo(pkg, repo);
+ return TRUE;
+ }
+ }
+
+ /* not found */
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Failed to ensure %1$s as repo %2$s not "
+ "found(%3$i repos loaded)"),
+ dnf_package_get_name(pkg),
+ dnf_package_get_reponame(pkg),
+ priv->repos->len);
+ return FALSE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_ensure_repo_list:
+ * @transaction: a #DnfTransaction instance.
+ * @pkglist: A #GPtrArray *
+ * @error: A #GError or %NULL
+ *
+ * Ensures the #DnfRepo is set on the #GPtrArray *if not already set.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ */
+gboolean
+dnf_transaction_ensure_repo_list(DnfTransaction *transaction, GPtrArray *pkglist, GError **error) try
+{
+ for (guint i = 0; i < pkglist->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, i));
+ if (!dnf_transaction_ensure_repo(transaction, pkg, error))
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_transaction_gpgcheck_package(DnfTransaction *transaction, DnfPackage *pkg, GError **error) try
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ GError *error_local = NULL;
+ DnfRepo *repo;
+ const gchar *fn;
+
+ /* ensure the filename is set */
+ if (!dnf_transaction_ensure_repo(transaction, pkg, error)) {
+ g_prefix_error(error, _("Failed to check untrusted: "));
+ return FALSE;
+ }
+
+ /* find the location of the local file */
+ fn = dnf_package_get_filename(pkg);
+ if (fn == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_NOT_FOUND,
+ _("Downloaded file for %s not found"),
+ dnf_package_get_name(pkg));
+ return FALSE;
+ }
+
+ /* check file */
+ if (!dnf_keyring_check_untrusted_file(priv->keyring, fn, &error_local)) {
+
+ /* probably an i/o error */
+ if (!g_error_matches(error_local, DNF_ERROR, DNF_ERROR_GPG_SIGNATURE_INVALID)) {
+ g_propagate_error(error, error_local);
+ return FALSE;
+ }
+
+ /* if the repo is signed this is ALWAYS an error */
+ repo = dnf_package_get_repo(pkg);
+ if (repo != NULL && dnf_repo_get_gpgcheck(repo)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("package %1$s cannot be verified "
+ "and repo %2$s is GPG enabled: %3$s"),
+ dnf_package_get_nevra(pkg),
+ dnf_repo_get_id(repo),
+ error_local->message);
+ g_error_free(error_local);
+ return FALSE;
+ }
+
+ /* we can only install signed packages in this mode */
+ if ((priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) > 0) {
+ g_propagate_error(error, error_local);
+ return FALSE;
+ } else {
+ g_clear_error(&error_local);
+ }
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_check_untrusted:
+ * @transaction: Transaction
+ * @goal: Target goal
+ * @error: Error
+ *
+ * Verify GPG signatures for all pending packages to be changed as part
+ * of @goal.
+ */
+gboolean
+dnf_transaction_check_untrusted(DnfTransaction *transaction, HyGoal goal, GError **error) try
+{
+ guint i;
+ g_autoptr(GPtrArray) install = NULL;
+
+ /* find a list of all the packages we might have to download */
+ install = dnf_goal_get_packages(goal,
+ DNF_PACKAGE_INFO_INSTALL,
+ DNF_PACKAGE_INFO_REINSTALL,
+ DNF_PACKAGE_INFO_DOWNGRADE,
+ DNF_PACKAGE_INFO_UPDATE,
+ -1);
+ if (install->len == 0)
+ return TRUE;
+
+ /* find any packages in untrusted repos */
+ for (i = 0; i < install->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(install, i));
+
+ if (!dnf_transaction_gpgcheck_package(transaction, pkg, error))
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_find_pkg_from_header:
+ **/
+static DnfPackage *
+dnf_find_pkg_from_header(GPtrArray *array, Header hdr)
+{
+ const gchar *arch;
+ const gchar *name;
+ const gchar *release;
+ const gchar *version;
+ guint epoch;
+ guint i;
+
+ /* get details */
+ name = headerGetString(hdr, RPMTAG_NAME);
+ epoch = headerGetNumber(hdr, RPMTAG_EPOCH);
+ version = headerGetString(hdr, RPMTAG_VERSION);
+ release = headerGetString(hdr, RPMTAG_RELEASE);
+ arch = headerGetString(hdr, RPMTAG_ARCH);
+
+ /* find in array */
+ for (i = 0; i < array->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(array, i));
+ if (g_strcmp0(name, dnf_package_get_name(pkg)) != 0)
+ continue;
+ if (g_strcmp0(version, dnf_package_get_version(pkg)) != 0)
+ continue;
+ if (g_strcmp0(release, dnf_package_get_release(pkg)) != 0)
+ continue;
+ if (g_strcmp0(arch, dnf_package_get_arch(pkg)) != 0)
+ continue;
+ if (epoch != dnf_package_get_epoch(pkg))
+ continue;
+ return pkg;
+ }
+ return NULL;
+}
+
+/**
+ * dnf_find_pkg_from_filename_suffix:
+ **/
+static DnfPackage *
+dnf_find_pkg_from_filename_suffix(GPtrArray *array, const gchar *filename_suffix)
+{
+ /* find in array */
+ for (guint i = 0; i < array->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(array, i));
+ auto filename = dnf_package_get_filename(pkg);
+ if (filename == NULL)
+ continue;
+ if (g_str_has_suffix(filename, filename_suffix))
+ return pkg;
+ }
+ return NULL;
+}
+
+/**
+ * dnf_find_pkg_from_name:
+ **/
+static DnfPackage *
+dnf_find_pkg_from_name(GPtrArray *array, const gchar *pkgname)
+{
+ guint i;
+
+ /* find in array */
+ for (i = 0; i < array->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(array, i));
+ if (g_strcmp0(dnf_package_get_name(pkg), pkgname) == 0)
+ return pkg;
+ }
+ return NULL;
+}
+
+static void
+_swdb_transaction_item_progress(libdnf::Swdb *swdb, DnfPackage *pkg)
+{
+ if (pkg == NULL) {
+ return;
+ }
+ const char *nevra = dnf_package_get_nevra(pkg);
+ if (nevra == NULL) {
+ return;
+ }
+ swdb->setItemDone(nevra);
+}
+
+/**
+ * dnf_transaction_ts_progress_cb:
+ **/
+static void *
+dnf_transaction_ts_progress_cb(const void *arg,
+ const rpmCallbackType what,
+ const rpm_loff_t amount,
+ const rpm_loff_t total,
+ fnpyKey key,
+ void *data)
+{
+ DnfTransaction *transaction = DNF_TRANSACTION(data);
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ const char *filename = (const char *)key;
+ const gchar *name = NULL;
+ gboolean ret;
+ guint percentage;
+ guint speed;
+ Header hdr = (Header)arg;
+ DnfPackage *pkg = NULL;
+ DnfStateAction action;
+ void *rc = NULL;
+ libdnf::Swdb *swdb = priv->swdb;
+ g_autoptr(GError) error_local = NULL;
+
+ if (hdr != NULL)
+ name = headerGetString(hdr, RPMTAG_NAME);
+ g_debug("phase: %u(%i/%i, %s/%s)",
+ (uint)what,
+ (gint32)amount,
+ (gint32)total,
+ (const gchar *)key,
+ name);
+
+ switch (what) {
+ case RPMCALLBACK_INST_OPEN_FILE:
+
+ /* valid? */
+ if (filename == NULL || filename[0] == '\0')
+ return NULL;
+
+ /* open the file and return file descriptor */
+ priv->fd = Fopen(filename, "r.ufdio");
+ return (void *)priv->fd;
+ break;
+
+ case RPMCALLBACK_INST_CLOSE_FILE:
+
+ /* just close the file */
+ if (priv->fd != NULL) {
+ Fclose(priv->fd);
+ priv->fd = NULL;
+ }
+ break;
+
+ case RPMCALLBACK_INST_START:
+
+ /* find pkg */
+ pkg = dnf_find_pkg_from_filename_suffix(priv->install, filename);
+ if (pkg == NULL)
+ g_assert_not_reached();
+
+ /* map to correct action code */
+ action = dnf_package_get_action(pkg);
+ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL)
+ action = DNF_STATE_ACTION_INSTALL;
+
+ /* set the pkgid if not already set */
+ if (dnf_package_get_pkgid(pkg) == NULL) {
+ const gchar *pkgid;
+ pkgid = headerGetString(hdr, RPMTAG_SHA1HEADER);
+ if (pkgid != NULL) {
+ g_debug("setting %s pkgid %s", name, pkgid);
+ dnf_package_set_pkgid(pkg, pkgid);
+ }
+ }
+
+ /* install start */
+ priv->step = DNF_TRANSACTION_STEP_WRITING;
+ priv->child = dnf_state_get_child(priv->state);
+ dnf_state_action_start(priv->child, action, dnf_package_get_package_id(pkg));
+ g_debug("install start: %s size=%i", filename, (gint32)total);
+ break;
+
+ case RPMCALLBACK_UNINST_START:
+
+ /* find pkg */
+ pkg = dnf_find_pkg_from_header(priv->remove, hdr);
+ if (pkg == NULL && filename != NULL) {
+ pkg = dnf_find_pkg_from_filename_suffix(priv->remove, filename);
+ }
+ if (pkg == NULL && name != NULL)
+ pkg = dnf_find_pkg_from_name(priv->remove, name);
+ if (pkg == NULL && name != NULL)
+ pkg = dnf_find_pkg_from_name(priv->remove_helper, name);
+ if (pkg == NULL) {
+ g_warning("cannot find %s in uninst-start", name);
+ priv->step = DNF_TRANSACTION_STEP_WRITING;
+ break;
+ }
+
+ /* map to correct action code */
+ action = dnf_package_get_action(pkg);
+ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL)
+ action = DNF_STATE_ACTION_REMOVE;
+
+ /* remove start */
+ priv->step = DNF_TRANSACTION_STEP_WRITING;
+ priv->child = dnf_state_get_child(priv->state);
+ dnf_state_action_start(priv->child, action, dnf_package_get_package_id(pkg));
+ g_debug("remove start: %s size=%i", filename, (gint32)total);
+ break;
+
+ case RPMCALLBACK_TRANS_PROGRESS:
+ case RPMCALLBACK_INST_PROGRESS:
+
+ /* we're preparing the transaction */
+ if (priv->step == DNF_TRANSACTION_STEP_PREPARING ||
+ priv->step == DNF_TRANSACTION_STEP_IGNORE) {
+ g_debug("ignoring preparing %i / %i", (gint32)amount, (gint32)total);
+ break;
+ }
+
+ /* work out speed */
+ speed = (amount - priv->last_progress) / g_timer_elapsed(priv->timer, NULL);
+ dnf_state_set_speed(priv->state, speed);
+ priv->last_progress = amount;
+ g_timer_reset(priv->timer);
+
+ /* progress */
+ percentage = (100.0f / (gfloat)total) * (gfloat)amount;
+ if (priv->child != NULL)
+ dnf_state_set_percentage(priv->child, percentage);
+
+ /* update UI */
+ pkg = dnf_find_pkg_from_header(priv->install, hdr);
+ if (pkg == NULL) {
+ pkg = dnf_find_pkg_from_filename_suffix(priv->install, filename);
+ }
+ if (pkg == NULL) {
+ g_debug("cannot find %s(%s)", filename, name);
+ break;
+ }
+
+ dnf_state_set_package_progress(
+ priv->state, dnf_package_get_package_id(pkg), DNF_STATE_ACTION_INSTALL, percentage);
+ break;
+
+ case RPMCALLBACK_UNINST_PROGRESS:
+
+ /* we're preparing the transaction */
+ if (priv->step == DNF_TRANSACTION_STEP_PREPARING ||
+ priv->step == DNF_TRANSACTION_STEP_IGNORE) {
+ g_debug("ignoring preparing %i / %i", (gint32)amount, (gint32)total);
+ break;
+ }
+
+ /* progress */
+ percentage = (100.0f / (gfloat)total) * (gfloat)amount;
+ if (priv->child != NULL)
+ dnf_state_set_percentage(priv->child, percentage);
+
+ /* update UI */
+ pkg = dnf_find_pkg_from_header(priv->remove, hdr);
+ if (pkg == NULL && filename != NULL) {
+ pkg = dnf_find_pkg_from_filename_suffix(priv->remove, filename);
+ }
+ if (pkg == NULL && name != NULL)
+ pkg = dnf_find_pkg_from_name(priv->remove, name);
+ if (pkg == NULL && name != NULL)
+ pkg = dnf_find_pkg_from_name(priv->remove_helper, name);
+ if (pkg == NULL) {
+ g_warning("cannot find %s in uninst-progress", name);
+ break;
+ }
+
+ /* map to correct action code */
+ action = dnf_package_get_action(pkg);
+ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL)
+ action = DNF_STATE_ACTION_REMOVE;
+
+ dnf_state_set_package_progress(
+ priv->state, dnf_package_get_package_id(pkg), action, percentage);
+ break;
+
+ case RPMCALLBACK_TRANS_START:
+
+ /* we setup the state */
+ g_debug("preparing transaction with %i items", (gint32)total);
+ if (priv->step == DNF_TRANSACTION_STEP_IGNORE)
+ break;
+
+ dnf_state_set_number_steps(priv->state, total);
+ priv->step = DNF_TRANSACTION_STEP_PREPARING;
+ break;
+
+ case RPMCALLBACK_TRANS_STOP:
+
+ /* don't do anything */
+ break;
+
+ case RPMCALLBACK_INST_STOP:
+ pkg = dnf_find_pkg_from_header(priv->install, hdr);
+ if (pkg == NULL && filename != NULL) {
+ pkg = dnf_find_pkg_from_filename_suffix(priv->install, filename);
+ }
+
+ // transaction item install complete
+ _swdb_transaction_item_progress(swdb, pkg);
+
+ /* phase complete */
+ ret = dnf_state_done(priv->state, &error_local);
+ if (!ret) {
+ g_warning("state increment failed: %s", error_local->message);
+ }
+ break;
+
+ case RPMCALLBACK_UNINST_STOP:
+
+ pkg = dnf_find_pkg_from_header(priv->remove, hdr);
+ if (pkg == NULL) {
+ pkg = dnf_find_pkg_from_header(priv->remove_helper, hdr);
+ }
+ if (pkg == NULL && filename != NULL) {
+ pkg = dnf_find_pkg_from_filename_suffix(priv->remove, filename);
+ }
+ if (pkg == NULL && name != NULL) {
+ pkg = dnf_find_pkg_from_name(priv->remove, name);
+ }
+ if (pkg == NULL && name != NULL) {
+ pkg = dnf_find_pkg_from_name(priv->remove_helper, name);
+ }
+
+ // transaction item remove complete
+ _swdb_transaction_item_progress(swdb, pkg);
+
+ /* phase complete */
+ ret = dnf_state_done(priv->state, &error_local);
+ if (!ret) {
+ g_warning("state increment failed: %s", error_local->message);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return rc;
+}
+
+/**
+ * dnf_rpm_verbosity_string_to_value:
+ **/
+static gint
+dnf_rpm_verbosity_string_to_value(const gchar *value)
+{
+ if (g_strcmp0(value, "critical") == 0)
+ return RPMLOG_CRIT;
+ if (g_strcmp0(value, "emergency") == 0)
+ return RPMLOG_EMERG;
+ if (g_strcmp0(value, "error") == 0)
+ return RPMLOG_ERR;
+ if (g_strcmp0(value, "warn") == 0)
+ return RPMLOG_WARNING;
+ if (g_strcmp0(value, "debug") == 0)
+ return RPMLOG_DEBUG;
+ if (g_strcmp0(value, "info") == 0)
+ return RPMLOG_INFO;
+ return RPMLOG_EMERG;
+}
+
+/**
+ * dnf_transaction_delete_packages:
+ **/
+static gboolean
+dnf_transaction_delete_packages(DnfTransaction *transaction, DnfState *state, GError **error)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ DnfState *state_local;
+ const gchar *cachedir;
+ guint i;
+
+ /* nothing to delete? */
+ if (priv->install->len == 0)
+ return TRUE;
+
+ /* get the cachedir so we only delete packages in the actual
+ * cache, not local-install packages */
+ cachedir = dnf_context_get_cache_dir(priv->context);
+ if (cachedir == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_FAILED_CONFIG_PARSING,
+ _("Failed to get value for CacheDir"));
+ return FALSE;
+ }
+
+ /* delete each downloaded file */
+ state_local = dnf_state_get_child(state);
+ dnf_state_set_number_steps(state_local, priv->install->len);
+ for (i = 0; i < priv->install->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(priv->install, i));
+
+ /* don't delete files not in the repo */
+ auto filename = dnf_package_get_filename(pkg);
+ if (g_str_has_prefix(filename, cachedir)) {
+ g_autoptr(GFile) file = NULL;
+ file = g_file_new_for_path(filename);
+ if (!g_file_delete(file, NULL, error))
+ return FALSE;
+ }
+
+ /* done */
+ if (!dnf_state_done(state_local, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int64_t
+_get_current_time()
+{
+ g_autoptr(GDateTime) t_struct = g_date_time_new_now_utc();
+ return g_date_time_to_unix(t_struct);
+}
+
+/**
+ * We've used dnf_package_set_pkgid() when running the transaction so we can
+ * avoid the lookup in the rpmdb.
+ **/
+static void
+_history_write_item(DnfPackage *pkg, libdnf::Swdb *swdb, libdnf::TransactionItemAction action, libdnf::TransactionItemReason reason)
+{
+ auto rpm = swdb->createRPMItem();
+ rpm->setName(dnf_package_get_name(pkg));
+ rpm->setEpoch(dnf_package_get_epoch(pkg));
+ rpm->setVersion(dnf_package_get_version(pkg));
+ rpm->setRelease(dnf_package_get_release(pkg));
+ rpm->setArch(dnf_package_get_arch(pkg));
+ rpm->save();
+
+ if (reason == libdnf::TransactionItemReason::UNKNOWN) {
+ reason = swdb->resolveRPMTransactionItemReason(rpm->getName(), rpm->getArch(), -2);
+ }
+
+ auto transItem = swdb->addItem(
+ std::dynamic_pointer_cast< libdnf::Item >(rpm), dnf_package_get_reponame(pkg), action, reason);
+}
+
+static gboolean
+dnf_transaction_check_free_space(DnfTransaction *transaction, GError **error)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ const gchar *cachedir;
+ guint64 download_size;
+ guint64 free_space;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GFileInfo) filesystem_info = NULL;
+
+ download_size = dnf_package_array_get_download_size(priv->pkgs_to_download);
+
+ cachedir = dnf_context_get_cache_dir(priv->context);
+ if (cachedir == NULL) {
+ g_set_error_literal(error,
+ DNF_ERROR,
+ DNF_ERROR_FAILED_CONFIG_PARSING,
+ _("Failed to get value for CacheDir"));
+ return FALSE;
+ }
+
+ file = g_file_new_for_path(cachedir);
+ filesystem_info =
+ g_file_query_filesystem_info(file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, error);
+ if (filesystem_info == NULL) {
+ g_prefix_error(error, _("Failed to get filesystem free size for %s: "), cachedir);
+ return FALSE;
+ }
+
+ if (!g_file_info_has_attribute(filesystem_info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FAILED,
+ _("Failed to get filesystem free size for %s"),
+ cachedir);
+ return FALSE;
+ }
+
+ free_space =
+ g_file_info_get_attribute_uint64(filesystem_info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+ if (free_space < download_size) {
+ g_autofree gchar *formatted_download_size = NULL;
+ g_autofree gchar *formatted_free_size = NULL;
+
+ formatted_download_size = g_format_size(download_size);
+ formatted_free_size = g_format_size(free_space);
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_NO_SPACE,
+ _("Not enough free space in %1$s: needed %2$s, available %3$s"),
+ cachedir,
+ formatted_download_size,
+ formatted_free_size);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * dnf_transaction_download:
+ * @transaction: a #DnfTransaction instance.
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ *
+ * Downloads all the packages needed for a transaction.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_transaction_download(DnfTransaction *transaction, DnfState *state, GError **error) try
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+
+ /* check that we have enough free space */
+ if (!dnf_transaction_check_free_space(transaction, error))
+ return FALSE;
+
+ /* just download the list */
+ return dnf_package_array_download(priv->pkgs_to_download, NULL, state, error);
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_depsolve:
+ * @transaction: a #DnfTransaction instance.
+ * @goal: A #HyGoal
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ *
+ * Depsolves the transaction.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_transaction_depsolve(DnfTransaction *transaction, HyGoal goal, DnfState *state, GError **error) try
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ gboolean valid;
+ g_autoptr(GPtrArray) packages = NULL;
+
+ /* depsolve */
+ if (!priv->dont_solve_goal) {
+ if (!dnf_goal_depsolve(goal, DNF_ALLOW_UNINSTALL, error)) {
+ return FALSE;
+ }
+ }
+
+ /* find a list of all the packages we have to download */
+ g_ptr_array_set_size(priv->pkgs_to_download, 0);
+ packages = dnf_goal_get_packages(goal,
+ DNF_PACKAGE_INFO_INSTALL,
+ DNF_PACKAGE_INFO_REINSTALL,
+ DNF_PACKAGE_INFO_DOWNGRADE,
+ DNF_PACKAGE_INFO_UPDATE,
+ -1);
+ g_debug("Goal has %u packages", packages->len);
+ for (guint i = 0; i < packages->len; i++) {
+ auto pkg = static_cast< DnfPackage * >(g_ptr_array_index(packages, i));
+
+ /* get correct package repo */
+ if (!dnf_transaction_ensure_repo(transaction, pkg, error))
+ return FALSE;
+
+ /* this is a local file */
+ if (g_strcmp0(dnf_package_get_reponame(pkg), HY_CMDLINE_REPO_NAME) == 0) {
+ continue;
+ }
+
+ /* check package exists and checksum is okay */
+ if (!dnf_package_check_filename(pkg, &valid, error))
+ return FALSE;
+
+ /* package needs to be downloaded */
+ if (!valid) {
+ g_ptr_array_add(priv->pkgs_to_download, g_object_ref(pkg));
+ }
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_reset:
+ */
+static void
+dnf_transaction_reset(DnfTransaction *transaction)
+{
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+
+ /* reset */
+ priv->child = NULL;
+ g_ptr_array_set_size(priv->pkgs_to_download, 0);
+ rpmtsEmpty(priv->ts);
+ rpmtsSetNotifyCallback(priv->ts, NULL, NULL);
+
+ /* clear */
+ if (priv->install != NULL) {
+ g_ptr_array_unref(priv->install);
+ priv->install = NULL;
+ }
+ if (priv->remove != NULL) {
+ g_ptr_array_unref(priv->remove);
+ priv->remove = NULL;
+ }
+ if (priv->remove_helper != NULL) {
+ g_ptr_array_unref(priv->remove_helper);
+ priv->remove_helper = NULL;
+ }
+ if (priv->erased_by_package_hash != NULL) {
+ g_hash_table_unref(priv->erased_by_package_hash);
+ priv->erased_by_package_hash = NULL;
+ }
+}
+
+/**
+ * dnf_transaction_import_keys:
+ * @transaction: a #DnfTransaction instance.
+ * @error: A #GError or %NULL
+ *
+ * Imports all keys from /etc/pki/rpm-gpg as well as any
+ * downloaded per-repo keys. Note this is called automatically
+ * by dnf_transaction_commit().
+ **/
+gboolean
+dnf_transaction_import_keys(DnfTransaction *transaction, GError **error) try
+{
+ guint i;
+
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ /* import all system wide GPG keys */
+ if (!dnf_keyring_add_public_keys(priv->keyring, error))
+ return FALSE;
+
+ /* import downloaded repo GPG keys */
+ for (i = 0; i < priv->repos->len; i++) {
+ auto repo = static_cast< DnfRepo * >(g_ptr_array_index(priv->repos, i));
+ g_auto(GStrv) pubkeys = dnf_repo_get_public_keys(repo);
+
+ /* does this file actually exist */
+ for (char **iter = pubkeys; iter && *iter; iter++) {
+ const char *pubkey = *iter;
+ if (g_file_test(pubkey, G_FILE_TEST_EXISTS)) {
+ /* import */
+ if (!dnf_keyring_add_public_key(priv->keyring, pubkey, error))
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_commit:
+ * @transaction: a #DnfTransaction instance.
+ * @goal: A #HyGoal
+ * @state: A #DnfState
+ * @error: A #GError or %NULL
+ *
+ * Commits a transaction by installing and removing packages.
+ *
+ * NOTE: If this fails, you need to call dnf_transaction_depsolve() again.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state, GError **error) try
+{
+ const gchar *filename;
+ const gchar *tmp;
+ gboolean allow_untrusted;
+ gboolean is_update;
+ gboolean ret = FALSE;
+ gint rc;
+ gint verbosity;
+ guint i;
+ guint j;
+ DnfState *state_local;
+ GPtrArray *all_obsoleted;
+ GPtrArray *pkglist;
+ DnfPackage *pkg;
+ DnfPackage *pkg_tmp;
+ rpmprobFilterFlags problems_filter = 0;
+ rpmtransFlags rpmts_flags = RPMTRANS_FLAG_NONE;
+ DnfTransactionPrivate *priv = GET_PRIVATE(transaction);
+ libdnf::Swdb *swdb = priv->swdb;
+ PluginHookContextTransactionData data{PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION, transaction, goal, state};
+ DnfSack * sack = hy_goal_get_sack(goal);
+ std::unique_ptr<char, decltype(free)*> rpmdb_cookie_uptr{nullptr, free};
+ std::string rpmdb_cookie;
+
+ /* take lock */
+ ret = dnf_state_take_lock(state, DNF_LOCK_TYPE_RPMDB, DNF_LOCK_MODE_PROCESS, error);
+ if (!ret)
+ goto out;
+
+ /* set state */
+ if (priv->flags & DNF_TRANSACTION_FLAG_TEST) {
+ ret = dnf_state_set_steps(state,
+ error,
+ 2, /* install */
+ 2, /* remove */
+ 10, /* test-commit */
+ 86, /* commit */
+ -1);
+ } else {
+ ret = dnf_state_set_steps(state,
+ error,
+ 2, /* install */
+ 2, /* remove */
+ 10, /* test-commit */
+ 83, /* commit */
+ 1, /* write yumDB */
+ 2, /* delete files */
+ -1);
+ }
+ if (!ret)
+ goto out;
+
+ ret = dnf_transaction_import_keys(transaction, error);
+ if (!ret)
+ goto out;
+
+ /* find any packages without valid GPG signatures */
+ ret = dnf_transaction_check_untrusted(transaction, goal, error);
+ if (!ret)
+ goto out;
+
+ // initialize SWDB transaction
+ swdb->initTransaction();
+
+ dnf_state_action_start(state, DNF_STATE_ACTION_REQUEST, NULL);
+
+ /* get verbosity from the config file */
+ tmp = dnf_context_get_rpm_verbosity(priv->context);
+ verbosity = dnf_rpm_verbosity_string_to_value(tmp);
+ rpmSetVerbosity(verbosity);
+
+ /* setup the transaction */
+ tmp = dnf_context_get_install_root(priv->context);
+ rc = rpmtsSetRootDir(priv->ts, tmp);
+ if (rc < 0) {
+ ret = FALSE;
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, _("failed to set root"));
+ goto out;
+ }
+ rpmtsSetNotifyCallback(priv->ts, dnf_transaction_ts_progress_cb, transaction);
+
+ /* add things to install */
+ state_local = dnf_state_get_child(state);
+ priv->install = dnf_goal_get_packages(goal,
+ DNF_PACKAGE_INFO_INSTALL,
+ DNF_PACKAGE_INFO_REINSTALL,
+ DNF_PACKAGE_INFO_DOWNGRADE,
+ DNF_PACKAGE_INFO_UPDATE,
+ -1);
+ if (priv->install->len > 0)
+ dnf_state_set_number_steps(state_local, priv->install->len);
+ for (i = 0; i < priv->install->len; i++) {
+
+ pkg = static_cast< DnfPackage * >(g_ptr_array_index(priv->install, i));
+ ret = dnf_transaction_ensure_repo(transaction, pkg, error);
+ if (!ret)
+ goto out;
+
+ DnfStateAction action = dnf_package_get_action(pkg);
+
+ /* add the install */
+ filename = dnf_package_get_filename(pkg);
+ allow_untrusted = (priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) == 0;
+ is_update = action == DNF_STATE_ACTION_UPDATE || action == DNF_STATE_ACTION_DOWNGRADE;
+ if (action == DNF_STATE_ACTION_REINSTALL) {
+ ret = dnf_rpmts_add_reinstall_filename(priv->ts, filename, allow_untrusted, error);
+ } else {
+ ret = dnf_rpmts_add_install_filename2(
+ priv->ts, filename, allow_untrusted, is_update, pkg, error);
+ }
+ if (!ret)
+ goto out;
+
+ // resolve swdb reason
+ libdnf::TransactionItemAction swdbAction = libdnf::TransactionItemAction::INSTALL;
+ if (action == DNF_STATE_ACTION_UPDATE) {
+ swdbAction = libdnf::TransactionItemAction::UPGRADE;
+ } else if (action == DNF_STATE_ACTION_DOWNGRADE) {
+ swdbAction = libdnf::TransactionItemAction::DOWNGRADE;
+ } else if (action == DNF_STATE_ACTION_REINSTALL) {
+ swdbAction = libdnf::TransactionItemAction::REINSTALL;
+ }
+
+ libdnf::TransactionItemReason swdbReason;
+ if (swdbAction != libdnf::TransactionItemAction::INSTALL) {
+ /* Placeholder to be fetched later from history */
+ swdbReason = libdnf::TransactionItemReason::UNKNOWN;
+ } else switch (hy_goal_get_reason(goal, pkg)) {
+ case HY_REASON_USER:
+ swdbReason = libdnf::TransactionItemReason::USER;
+ break;
+ case HY_REASON_DEP:
+ swdbReason = libdnf::TransactionItemReason::DEPENDENCY;
+ break;
+ default:
+ swdbReason = libdnf::TransactionItemReason::UNKNOWN;
+ }
+
+ // add item to swdb transaction
+ _history_write_item(pkg, swdb, swdbAction, swdbReason);
+
+ /* this section done */
+ ret = dnf_state_done(state_local, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* add things to remove */
+ priv->remove =
+ dnf_goal_get_packages(goal, DNF_PACKAGE_INFO_OBSOLETE, DNF_PACKAGE_INFO_REMOVE, -1);
+ for (i = 0; i < priv->remove->len; i++) {
+ pkg = static_cast< DnfPackage * >(g_ptr_array_index(priv->remove, i));
+ ret = dnf_rpmts_add_remove_pkg(priv->ts, pkg, error);
+ if (!ret)
+ goto out;
+
+ /* pre-get the pkgid, as this isn't possible to get after
+ * the sack is invalidated */
+ if (dnf_package_get_pkgid(pkg) == NULL) {
+ g_warning("failed to pre-get pkgid for %s", dnf_package_get_package_id(pkg));
+ }
+
+ libdnf::TransactionItemAction swdbAction = libdnf::TransactionItemAction::REMOVE;
+
+ /* are the things being removed actually being upgraded */
+ pkg_tmp = dnf_find_pkg_from_name(priv->install, dnf_package_get_name(pkg));
+ if (pkg_tmp != NULL) {
+ dnf_package_set_action(pkg, DNF_STATE_ACTION_CLEANUP);
+ if (dnf_package_evr_cmp(pkg, pkg_tmp)) {
+ swdbAction = libdnf::TransactionItemAction::UPGRADED;
+ } else {
+ swdbAction = libdnf::TransactionItemAction::DOWNGRADED;
+ }
+ }
+ _history_write_item(pkg, swdb, swdbAction, libdnf::TransactionItemReason::UNKNOWN);
+ }
+
+ /* add anything that gets obsoleted to a helper array which is used to
+ * map removed packages auto-added by rpm to actual DnfPackage's */
+ priv->remove_helper = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+ for (i = 0; i < priv->install->len; i++) {
+ pkg = static_cast< DnfPackage * >(g_ptr_array_index(priv->install, i));
+ is_update = dnf_package_get_action(pkg) == DNF_STATE_ACTION_UPDATE ||
+ dnf_package_get_action(pkg) == DNF_STATE_ACTION_DOWNGRADE;
+ if (!is_update)
+ continue;
+ pkglist = hy_goal_list_obsoleted_by_package(goal, pkg);
+
+ const char *pkg_name = dnf_package_get_name(pkg);
+
+ for (j = 0; j < pkglist->len; j++) {
+ pkg_tmp = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, j));
+ g_ptr_array_add(priv->remove_helper, g_object_ref(pkg_tmp));
+ dnf_package_set_action(pkg_tmp, DNF_STATE_ACTION_CLEANUP);
+
+ const char *pkg_tmp_name = dnf_package_get_name(pkg_tmp);
+
+ if (dnf_find_pkg_from_name(priv->remove, pkg_tmp_name) != NULL) {
+ // package is already in remove set - skip resolution
+ continue;
+ }
+
+ libdnf::TransactionItemAction swdbAction = libdnf::TransactionItemAction::OBSOLETED;
+ if (g_strcmp0(pkg_name, pkg_tmp_name) == 0) {
+ // names are identical - package is upgraded/downgraded
+ if (dnf_package_evr_cmp(pkg, pkg_tmp)) {
+ swdbAction = libdnf::TransactionItemAction::UPGRADED;
+ } else {
+ swdbAction = libdnf::TransactionItemAction::DOWNGRADED;
+ }
+ }
+
+ if (swdbAction == libdnf::TransactionItemAction::OBSOLETED
+ && dnf_find_pkg_from_name(priv->install, pkg_tmp_name) != NULL
+ && g_strcmp0(pkg_name, pkg_tmp_name) != 0) {
+ // If a package is obsoleted and there's a package with the same name
+ // in the install set, skip recording the obsolete in the history db
+ // because the package upgrade prevails over the obsolete.
+ //
+ // Example:
+ // grub2-tools-efi obsoletes grub2-tools # skip as grub2-tools is also upgraded
+ // grub2-tools upgrades grub2-tools
+ continue;
+ }
+
+ // TODO SWDB add pkg_tmp replaced_by pkg
+ _history_write_item(pkg_tmp, swdb, swdbAction, libdnf::TransactionItemReason::UNKNOWN);
+ }
+ g_ptr_array_unref(pkglist);
+ }
+
+ /* add reinstalled packages to a helper array which is used to
+ * map removed packages auto-added by rpm to actual DnfPackage's */
+ pkglist = dnf_goal_get_packages(goal, DNF_PACKAGE_INFO_REINSTALL, -1);
+ for (i = 0; i < pkglist->len; i++) {
+ pkg_tmp = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, i));
+ g_ptr_array_add(priv->remove_helper, g_object_ref(pkg_tmp));
+ }
+ g_ptr_array_unref(pkglist);
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* map updated packages to their previous versions */
+ priv->erased_by_package_hash =
+ g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_object_unref);
+ all_obsoleted = hy_goal_list_obsoleted(goal, NULL);
+ for (i = 0; i < priv->install->len; i++) {
+ pkg = static_cast< DnfPackage * >(g_ptr_array_index(priv->install, i));
+ if (dnf_package_get_action(pkg) != DNF_STATE_ACTION_UPDATE &&
+ dnf_package_get_action(pkg) != DNF_STATE_ACTION_DOWNGRADE &&
+ dnf_package_get_action(pkg) != DNF_STATE_ACTION_REINSTALL)
+ continue;
+
+ pkglist = hy_goal_list_obsoleted_by_package(goal, pkg);
+ for (j = 0; j < pkglist->len; j++) {
+ pkg_tmp = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, j));
+ if (!hy_packagelist_has(all_obsoleted, pkg_tmp)) {
+ g_hash_table_insert(priv->erased_by_package_hash,
+ g_strdup(dnf_package_get_package_id(pkg)),
+ g_object_ref(pkg_tmp));
+ }
+ }
+ g_ptr_array_unref(pkglist);
+ }
+ g_ptr_array_unref(all_obsoleted);
+
+ /* generate ordering for the transaction */
+ rpmtsOrder(priv->ts);
+
+ /* run the test transaction */
+ if (dnf_context_get_check_transaction(priv->context)) {
+ g_debug("running test transaction");
+ dnf_state_action_start(state, DNF_STATE_ACTION_TEST_COMMIT, NULL);
+ priv->state = dnf_state_get_child(state);
+ priv->step = DNF_TRANSACTION_STEP_IGNORE;
+ /* the output value of rpmtsCheck is not meaningful */
+ rpmtsCheck(priv->ts);
+ dnf_state_action_stop(state);
+ ret = dnf_rpmts_look_for_problems(priv->ts, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* no signature checking, we've handled that already */
+ rpmtsSetVSFlags(priv->ts, _RPMVSF_NOSIGNATURES | _RPMVSF_NODIGESTS);
+
+ /* filter diskspace */
+ if (!dnf_context_get_check_disk_space(priv->context))
+ problems_filter |= RPMPROB_FILTER_DISKSPACE;
+ if (priv->flags & DNF_TRANSACTION_FLAG_ALLOW_REINSTALL)
+ problems_filter |= RPMPROB_FILTER_REPLACEPKG;
+ if (priv->flags & DNF_TRANSACTION_FLAG_ALLOW_DOWNGRADE)
+ problems_filter |= RPMPROB_FILTER_OLDPACKAGE;
+
+ if (priv->flags & DNF_TRANSACTION_FLAG_NODOCS)
+ rpmts_flags |= RPMTRANS_FLAG_NODOCS;
+
+ if (priv->flags & DNF_TRANSACTION_FLAG_TEST) {
+ /* run the transaction in test mode */
+ rpmts_flags |= RPMTRANS_FLAG_TEST;
+
+ priv->state = dnf_state_get_child(state);
+ priv->step = DNF_TRANSACTION_STEP_IGNORE;
+ rpmtsSetFlags(priv->ts, rpmts_flags);
+ g_debug("Running transaction in test mode");
+ dnf_state_set_allow_cancel(state, FALSE);
+ rc = rpmtsRun(priv->ts, NULL, problems_filter);
+ if (rc < 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Error %i running transaction test"),
+ rc);
+ goto out;
+ }
+ if (rc > 0) {
+ ret = dnf_rpmts_look_for_problems(priv->ts, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* transaction test done; return */
+ ret = dnf_state_done(state, error);
+ goto out;
+ }
+
+ if (!dnf_context_plugin_hook(priv->context, PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION, &data, nullptr))
+ goto out;
+
+ // Open rpm database if it is not already open
+ if (!rpmtsGetRdb(priv->ts)) {
+ rc = rpmtsOpenDB(priv->ts, rpmtsGetDBMode(priv->ts));
+ if (rc != 0) {
+ ret = FALSE;
+ g_set_error(
+ error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, _("Error %i opening rpm database"), rc);
+ goto out;
+ }
+ }
+
+ rpmdb_cookie_uptr.reset(rpmdbCookie(rpmtsGetRdb(priv->ts)));
+ rpmdb_cookie = libdnf::string::fromCstring(rpmdb_cookie_uptr.get());
+ if (rpmdb_cookie.empty()) {
+ g_critical(_("The rpmdbCookie() function did not return cookie of rpm database."));
+ }
+ // FIXME get commandline
+ swdb->beginTransaction(_get_current_time(), rpmdb_cookie, "", priv->uid);
+
+ /* run the transaction */
+ priv->state = dnf_state_get_child(state);
+ priv->step = DNF_TRANSACTION_STEP_STARTED;
+ rpmtsSetFlags(priv->ts, rpmts_flags);
+ g_debug("Running actual transaction");
+ dnf_state_set_allow_cancel(state, FALSE);
+ rc = rpmtsRun(priv->ts, NULL, problems_filter);
+ if (rc < 0) {
+ ret = FALSE;
+ g_set_error(
+ error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, _("Error %i running transaction"), rc);
+ goto out;
+ }
+ if (rc > 0) {
+ ret = dnf_rpmts_look_for_problems(priv->ts, error);
+ if (!ret)
+ goto out;
+ }
+
+ /* hmm, nothing was done... */
+ if (priv->step != DNF_TRANSACTION_STEP_WRITING) {
+ if (priv->install->len > 0 || priv->remove->len > 0) {
+ ret = FALSE;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("Transaction did not go to writing phase, "
+ "but returned no error(%i)"),
+ priv->step);
+ goto out;
+ }
+ }
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ rpmdb_cookie_uptr.reset(rpmdbCookie(rpmtsGetRdb(priv->ts)));
+ rpmdb_cookie = libdnf::string::fromCstring(rpmdb_cookie_uptr.get());
+ if (rpmdb_cookie.empty()) {
+ g_critical(_("The rpmdbCookie() function did not return cookie of rpm database."));
+ }
+ swdb->endTransaction(_get_current_time(), rpmdb_cookie, libdnf::TransactionState::DONE);
+ swdb->closeTransaction();
+
+ data.hookId = PLUGIN_HOOK_ID_CONTEXT_TRANSACTION;
+ if (!dnf_context_plugin_hook(priv->context, PLUGIN_HOOK_ID_CONTEXT_TRANSACTION, &data, nullptr))
+ goto out;
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* remove the files we downloaded */
+ if (!dnf_context_get_keep_cache(priv->context)) {
+ state_local = dnf_state_get_child(state);
+ ret = dnf_transaction_delete_packages(transaction, state_local, error);
+ if (!ret)
+ goto out;
+ }
+
+ if (sack) {
+ if (auto moduleContainer = dnf_sack_get_module_container(sack)) {
+ moduleContainer->save();
+ moduleContainer->updateFailSafeData();
+ }
+ }
+
+ /* all sacks are invalid now */
+ dnf_context_invalidate_full(priv->context,
+ "transaction performed",
+ DNF_CONTEXT_INVALIDATE_FLAG_RPMDB |
+ DNF_CONTEXT_INVALIDATE_FLAG_ENROLLMENT);
+
+ /* this section done */
+ ret = dnf_state_done(state, error);
+out:
+ dnf_transaction_reset(transaction);
+ dnf_state_release_locks(state);
+ return ret;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_transaction_new:
+ * @context: a #DnfContext instance.
+ *
+ * Creates a new #DnfTransaction.
+ *
+ * Returns:(transfer full): a #DnfTransaction
+ *
+ * Since: 0.1.0
+ **/
+DnfTransaction *
+dnf_transaction_new(DnfContext *context)
+{
+ auto transaction = DNF_TRANSACTION(g_object_new(DNF_TYPE_TRANSACTION, NULL));
+ auto priv = GET_PRIVATE(transaction);
+ auto install_root = dnf_context_get_install_root(context);
+ std::string dbPath;
+ if (dnf_context_get_write_history(context)) {
+ gchar *tmp_path = g_build_filename(install_root, libdnf::Swdb::defaultPath, NULL);
+ dbPath = std::string(tmp_path);
+ g_free(tmp_path);
+ } else {
+ dbPath = ":memory:";
+ }
+ priv->swdb = new libdnf::Swdb(dbPath);
+ priv->context = context;
+ g_object_add_weak_pointer(G_OBJECT(priv->context), (void **)&priv->context);
+ priv->ts = rpmtsCreate();
+ rpmtsSetRootDir(priv->ts, install_root);
+ priv->keyring = rpmtsGetKeyring(priv->ts, 1);
+ return transaction;
+}
+
+DnfTransaction *
+hookContextTransactionGetTransaction(DnfPluginHookData * data)
+{
+ if (!data) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with data == nullptr", __func__));
+ return nullptr;
+ }
+ if (data->hookId != PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION &&
+ data->hookId != PLUGIN_HOOK_ID_CONTEXT_TRANSACTION) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with hookId == %i", __func__, data->hookId));
+ return nullptr;
+ }
+ return (static_cast<PluginHookContextTransactionData *>(data))->transaction;
+}
+
+HyGoal
+hookContextTransactionGetGoal(DnfPluginHookData * data)
+{
+ if (!data) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with data == nullptr", __func__));
+ return nullptr;
+ }
+ if (data->hookId != PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION &&
+ data->hookId != PLUGIN_HOOK_ID_CONTEXT_TRANSACTION) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with hookId == %i", __func__, data->hookId));
+ return nullptr;
+ }
+ return (static_cast<PluginHookContextTransactionData *>(data))->goal;
+}
+
+DnfState *
+hookContextTransactionGetState(DnfPluginHookData * data)
+{
+ if (!data) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with data == nullptr", __func__));
+ return nullptr;
+ }
+ if (data->hookId != PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION &&
+ data->hookId != PLUGIN_HOOK_ID_CONTEXT_TRANSACTION) {
+ auto logger(libdnf::Log::getLogger());
+ logger->error(tfm::format("%s: was called with hookId == %i", __func__, data->hookId));
+ return nullptr;
+ }
+ return (static_cast<PluginHookContextTransactionData *>(data))->state;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_TRANSACTION_H
+#define __DNF_TRANSACTION_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "hy-goal.h"
+#include "dnf-types.h"
+#include "dnf-context.h"
+#include "dnf-state.h"
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_TRANSACTION (dnf_transaction_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfTransaction, dnf_transaction, DNF, TRANSACTION, GObject)
+
+struct _DnfTransactionClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+/**
+ * DnfTransactionFlag:
+ * @DNF_TRANSACTION_FLAG_NONE: No flags
+ * @DNF_TRANSACTION_FLAG_ONLY_TRUSTED: Only install trusted packages
+ * @DNF_TRANSACTION_FLAG_ALLOW_REINSTALL: Allow package reinstallation
+ * @DNF_TRANSACTION_FLAG_ALLOW_DOWNGRADE: Allow package downrades
+ * @DNF_TRANSACTION_FLAG_NODOCS: Don't install documentation
+ * @DNF_TRANSACTION_FLAG_TEST: Only do a transaction test
+ *
+ * The transaction flags.
+ **/
+typedef enum {
+ DNF_TRANSACTION_FLAG_NONE = 0,
+ DNF_TRANSACTION_FLAG_ONLY_TRUSTED = 1 << 0,
+ DNF_TRANSACTION_FLAG_ALLOW_REINSTALL = 1 << 1,
+ DNF_TRANSACTION_FLAG_ALLOW_DOWNGRADE = 1 << 2,
+ DNF_TRANSACTION_FLAG_NODOCS = 1 << 3,
+ DNF_TRANSACTION_FLAG_TEST = 1 << 4,
+ /*< private >*/
+ DNF_TRANSACTION_FLAG_LAST
+} DnfTransactionFlag;
+
+DnfTransaction *dnf_transaction_new (DnfContext *context);
+
+/* getters */
+guint64 dnf_transaction_get_flags (DnfTransaction *transaction);
+GPtrArray *dnf_transaction_get_remote_pkgs (DnfTransaction *transaction);
+DnfDb *dnf_transaction_get_db (DnfTransaction *transaction);
+
+/* setters */
+void dnf_transaction_set_repos (DnfTransaction *transaction,
+ GPtrArray *repos);
+void dnf_transaction_set_uid (DnfTransaction *transaction,
+ guint uid);
+void dnf_transaction_set_flags (DnfTransaction *transaction,
+ guint64 flags);
+void dnf_transaction_set_dont_solve_goal (DnfTransaction *transaction,
+ gboolean dont_solve_goal);
+
+/* object methods */
+gboolean dnf_transaction_depsolve (DnfTransaction *transaction,
+ HyGoal goal,
+ DnfState *state,
+ GError **error);
+gboolean dnf_transaction_download (DnfTransaction *transaction,
+ DnfState *state,
+ GError **error);
+
+gboolean dnf_transaction_import_keys (DnfTransaction *transaction,
+ GError **error);
+
+gboolean dnf_transaction_gpgcheck_package (DnfTransaction *transaction,
+ DnfPackage *pkg,
+ GError **error);
+gboolean dnf_transaction_check_untrusted (DnfTransaction *transaction,
+ HyGoal goal,
+ GError **error);
+
+gboolean dnf_transaction_commit (DnfTransaction *transaction,
+ HyGoal goal,
+ DnfState *state,
+ GError **error);
+gboolean dnf_transaction_ensure_repo (DnfTransaction *transaction,
+ DnfPackage * pkg,
+ GError **error);
+gboolean dnf_transaction_ensure_repo_list (DnfTransaction *transaction,
+ GPtrArray * pkglist,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DNF_TRANSACTION_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2015 Colin Walters <walters@verbum.org>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __DNF_TYPES_H
+#define __DNF_TYPES_H
+
+#include <gio/gio.h>
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct ModulePackageContainer;
+ struct Swdb;
+ struct PackageSet;
+ struct Dependency;
+ struct DependencyContainer;
+}
+typedef struct libdnf::ModulePackageContainer DnfModulePackageContainer;
+typedef struct libdnf::Swdb DnfDb;
+typedef struct libdnf::PackageSet DnfPackageSet;
+typedef struct libdnf::Dependency DnfReldep;
+typedef struct libdnf::DependencyContainer DnfReldepList;
+#else
+typedef struct ModulePackageContainer DnfModulePackageContainer;
+typedef struct Swdb DnfDb;
+typedef struct PackageSet DnfPackageSet;
+typedef struct Dependency DnfReldep;
+typedef struct DependencyContainer DnfReldepList;
+#endif
+typedef struct _DnfContext DnfContext;
+typedef struct _DnfTransaction DnfTransaction;
+typedef struct _DnfRepoLoader DnfRepoLoader;
+typedef struct _DnfRepo DnfRepo;
+typedef struct _DnfState DnfState;
+typedef struct _DnfSack DnfSack;
+
+/**
+ * DnfError:
+ * @DNF_ERROR_FAILED: Failed with a non-specific error
+ * @DNF_ERROR_INTERNAL_ERROR: Something horrible happened
+ * @DNF_ERROR_CANNOT_GET_LOCK: Cannot get lock for action
+ * @DNF_ERROR_CANCELLED: The action was cancelled
+ * @DNF_ERROR_REPO_NOT_AVAILABLE: The repo is not available
+ * @DNF_ERROR_CANNOT_FETCH_SOURCE: Cannot fetch a software repo
+ * @DNF_ERROR_CANNOT_WRITE_REPO_CONFIG: Cannot write a repo config file
+ * @DNF_ERROR_PACKAGE_CONFLICTS: Package conflict exists
+ * @DNF_ERROR_NO_PACKAGES_TO_UPDATE: No packages to update
+ * @DNF_ERROR_PACKAGE_INSTALL_BLOCKED: Package install was blocked
+ * @DNF_ERROR_FILE_NOT_FOUND: File was not found
+ * @DNF_ERROR_UNFINISHED_TRANSACTION: An unfinished transaction exists
+ * @DNF_ERROR_GPG_SIGNATURE_INVALID: GPG signature was bad
+ * @DNF_ERROR_FILE_INVALID: File was invalid or could not be read
+ * @DNF_ERROR_REPO_NOT_FOUND: Source was not found
+ * @DNF_ERROR_FAILED_CONFIG_PARSING: Configuration could not be read
+ * @DNF_ERROR_PACKAGE_NOT_FOUND: Package was not found
+ * @DNF_ERROR_INVALID_ARCHITECTURE: Invalid architecture
+ * @DNF_ERROR_BAD_SELECTOR: The selector was in some way bad
+ * @DNF_ERROR_NO_SOLUTION: No solution was possible
+ * @DNF_ERROR_BAD_QUERY: The query was in some way bad
+ * @DNF_ERROR_NO_CAPABILITY: This feature was not available
+ * @DNF_ERROR_NO_SPACE: Out of disk space
+ * @DNF_ERROR_UNKNOWN_OPTION: Option with the requested name was not found
+ *
+ * The error code.
+ **/
+typedef enum {
+ DNF_ERROR_FAILED = 1, /* Since: 0.1.0 */
+ DNF_ERROR_INTERNAL_ERROR = 4, /* Since: 0.1.0 */
+ DNF_ERROR_CANNOT_GET_LOCK = 26, /* Since: 0.1.0 */
+ DNF_ERROR_CANCELLED = 17, /* Since: 0.1.0 */
+ DNF_ERROR_REPO_NOT_AVAILABLE = 37, /* Since: 0.1.0 */
+ DNF_ERROR_CANNOT_FETCH_SOURCE = 64, /* Since: 0.1.0 */
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG = 28, /* Since: 0.1.0 */
+ DNF_ERROR_PACKAGE_CONFLICTS = 36, /* Since: 0.1.0 */
+ DNF_ERROR_NO_PACKAGES_TO_UPDATE = 27, /* Since: 0.1.0 */
+ DNF_ERROR_PACKAGE_INSTALL_BLOCKED = 39, /* Since: 0.1.0 */
+ DNF_ERROR_FILE_NOT_FOUND = 42, /* Since: 0.1.0 */
+ DNF_ERROR_UNFINISHED_TRANSACTION = 66, /* Since: 0.1.0 */
+ DNF_ERROR_GPG_SIGNATURE_INVALID = 30, /* Since: 0.1.0 */
+ DNF_ERROR_FILE_INVALID = 38, /* Since: 0.1.0 */
+ DNF_ERROR_REPO_NOT_FOUND = 19, /* Since: 0.1.0 */
+ DNF_ERROR_FAILED_CONFIG_PARSING = 24, /* Since: 0.1.0 */
+ DNF_ERROR_PACKAGE_NOT_FOUND = 8, /* Since: 0.1.0 */
+ DNF_ERROR_NO_SPACE = 46, /* Since: 0.2.3 */
+ DNF_ERROR_INVALID_ARCHITECTURE, /* Since: 0.7.0 */
+ DNF_ERROR_BAD_SELECTOR, /* Since: 0.7.0 */
+ DNF_ERROR_NO_SOLUTION, /* Since: 0.7.0 */
+ DNF_ERROR_BAD_QUERY, /* Since: 0.7.0 */
+ DNF_ERROR_CANNOT_WRITE_CACHE, /* Since: 0.7.0 */
+ DNF_ERROR_NO_CAPABILITY, /* Since: 0.7.0 */
+ DNF_ERROR_REMOVAL_OF_PROTECTED_PKG, /* Since: 0.7.0 */
+ DNF_ERROR_UNKNOWN_OPTION, /* Since: 0.56.0 */
+ /*< private >*/
+ DNF_ERROR_LAST
+} DnfError;
+
+#define DNF_ERROR (dnf_error_quark ())
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+GQuark dnf_error_quark (void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-utils
+ * @short_description: Helper functions for libdnf
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * These functions are used internally in libdnf for various things.
+ */
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+
+#include "catch-error.hpp"
+#include "dnf-types.h"
+#include "dnf-utils.h"
+
+#include "utils/bgettext/bgettext-lib.h"
+
+/**
+ * dnf_error_quark:
+ *
+ * Returns a #GQuark for the error domain used in libdnf
+ *
+ * Returns: an error quark
+ **/
+GQuark
+dnf_error_quark(void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string("DnfError");
+ return quark;
+}
+
+/**
+ * dnf_realpath:
+ * @path: A relative path, e.g. "../../data/test"
+ *
+ * Converts relative paths to absolute ones.
+ *
+ * Returns: a new path, or %NULL
+ *
+ * Since: 0.1.7
+ **/
+gchar *
+dnf_realpath(const gchar *path)
+{
+ gchar *real = NULL;
+ char *temp;
+
+ /* don't trust realpath one little bit */
+ if (path == NULL)
+ return NULL;
+
+ /* glibc allocates us a buffer to try and fix some brain damage */
+ temp = realpath(path, NULL);
+ if (temp == NULL)
+ return NULL;
+ real = g_strdup(temp);
+ free(temp);
+ return real;
+}
+
+/**
+ * dnf_remove_recursive:
+ * @directory: A directory path
+ * @error: A #GError, or %NULL
+ *
+ * Removes a directory and its contents. Use with care.
+ *
+ * Returns: %FALSE if an error was set
+ *
+ * Since: 0.1.7
+ **/
+gboolean
+dnf_remove_recursive(const gchar *directory, GError **error) try
+{
+ const gchar *filename;
+ g_autoptr(GDir) dir = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ /* try to open */
+ dir = g_dir_open(directory, 0, &error_local);
+ if (dir == NULL) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot open directory %1$s: %2$s"),
+ directory, error_local->message);
+ return FALSE;
+ }
+
+ /* find each */
+ while ((filename = g_dir_read_name(dir))) {
+ g_autofree gchar *src = NULL;
+ src = g_build_filename(directory, filename, NULL);
+ if (g_file_test(src, G_FILE_TEST_IS_DIR)) {
+ if (!dnf_remove_recursive(src, error))
+ return FALSE;
+ } else {
+ g_debug("deleting file %s", src);
+ if (!dnf_ensure_file_unlinked(src, error))
+ return FALSE;
+ }
+ }
+
+ /* remove directory */
+ g_debug("deleting directory %s", directory);
+ if (g_remove(directory) != 0) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("failed to remove %s"), directory);
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+
+/**
+ * dnf_ensure_file_unlinked:
+ * @src_path: the path to the file
+ * @error: A #GError, or %NULL
+ *
+ * Remove a file based on the file path,
+ * refactored from dnf_remove_recursive() function
+ *
+ * Returns: %FALSE if an error was set
+ *
+ * Since 0.9.4
+ **/
+gboolean
+dnf_ensure_file_unlinked(const gchar *src_path, GError **error) try
+{
+ if ((unlink(src_path) != 0) && errno != ENOENT) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ "failed to unlink %s", src_path);
+ return FALSE;
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_delete_files_matching:
+ * @directory_path: the top level directory path to look at
+ * @patterns: the patterns that we are expecting from file/directory's name
+ * @error: a #GError instance, to track error
+ *
+ * Remove recursively all the files/directories that have names
+ * which match the patterns. Use with care
+ *
+ * There are several assumptions that are made in this function:
+ *
+ * 1: We assume the top level path( the path passed in initially)
+ * does not satisfy the criteria of matching the pattern
+ *
+ * 2: We assume the top level path itself is a directory initially
+ *
+ * Returns: %FALSE if failed to delete a file/directory
+ *
+ * Since: 0.9.4
+ **/
+gboolean
+dnf_delete_files_matching(const gchar* directory_path,
+ const char* const* patterns,
+ GError **error) try
+{
+ const gchar *filename;
+ g_autoptr(GDir) dir = NULL;
+
+ /* try to open the directory*/
+ dir = g_dir_open(directory_path, 0, error);
+ if (dir == NULL) {
+ g_prefix_error(error, "Cannot open directory %s: ", directory_path);
+ return FALSE;
+ }
+ /* In the directory, we read each file and check if their name matches one of the patterns */
+ while ((filename = g_dir_read_name(dir))) {
+ g_autofree gchar *src = g_build_filename(directory_path, filename, NULL);
+ if (g_file_test(src, G_FILE_TEST_IS_DIR)) {
+ gboolean matching = FALSE;
+ for (char **iter = (char **) patterns; iter && *iter; iter++) {
+ const char* pattern = *iter;
+ if (g_str_has_suffix(filename, pattern)) {
+ if (!dnf_remove_recursive(src, error))
+ return FALSE;
+ matching = TRUE;
+ break;
+ }
+ }
+ if (!matching) {
+ /* If the directory does not match pattern, keep looking into it */
+ if (!dnf_delete_files_matching(src, patterns, error))
+ return FALSE;
+ }
+ }
+ else {
+ /* This is for files in the directory, if matches, we directly delete it */
+ for (char **iter = (char **)patterns; iter && *iter; iter++) {
+ const char* pattern = *iter;
+ if (g_str_has_suffix(filename, pattern)) {
+ if (!dnf_ensure_file_unlinked(src, error))
+ return FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_get_file_contents_allow_noent:
+ * @path: File to open
+ * @out_contents: Output variable containing contents
+ * @out_length: Output variable containing length
+ * @error: A #GError, or %NULL
+ *
+ * Reads a file's contents. If the file does not exist, returns TRUE.
+ *
+ * Returns: %FALSE if an error other than G_FILE_ERROR_NOENT was set
+ *
+ * Since: 0.1.7
+ **/
+gboolean
+dnf_get_file_contents_allow_noent(const gchar *path,
+ gchar **out_contents,
+ gsize *out_length,
+ GError **error) try
+{
+ gsize length;
+ g_autofree gchar *contents = NULL;
+ g_autoptr(GError) local_error = NULL;
+
+ if (!g_file_get_contents(path, &contents, &length, &local_error)) {
+ if (g_error_matches(local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ return TRUE;
+
+ g_propagate_error(error, local_error);
+ return FALSE;
+ }
+
+ if (out_contents != NULL)
+ *out_contents = static_cast<gchar *>(g_steal_pointer (&contents));
+ if (out_length != NULL)
+ *out_length = length;
+
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_UTILS_H
+#define __DNF_UTILS_H
+
+#include <glib.h>
+
+#ifdef __cplusplus
+ #ifndef __has_cpp_attribute
+ #define __has_cpp_attribute(x) 0
+ #endif
+
+ #if __has_cpp_attribute(deprecated)
+ #define DEPRECATED(msg) [[deprecated(msg)]]
+ #endif
+#endif
+
+#ifndef DEPRECATED
+ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+ #define DEPRECATED(msg) __attribute__((__deprecated__(msg)))
+ #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
+ #define DEPRECATED(msg) __declspec(deprecated(msg))
+ #elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+ #define DEPRECATED(msg) __attribute__((__deprecated__))
+ #elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+ #define DEPRECATED(msg) __declspec(deprecated)
+ #else
+ #define DEPRECATED(msg)
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+gchar *dnf_realpath (const gchar *path);
+gboolean dnf_remove_recursive (const gchar *directory,
+ GError **error);
+gboolean dnf_ensure_file_unlinked (const gchar *src_path,
+ GError **error);
+gboolean dnf_delete_files_matching (const gchar *directory_path,
+ const char* const *patterns,
+ GError **error);
+gboolean dnf_get_file_contents_allow_noent (const gchar *path,
+ gchar **out_contents,
+ gsize *length,
+ GError **error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_UTILS_H */
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-version
+ * @short_description: Preprocessor macros for the libdnf version
+ * @include: libdnf.h
+ * @stability: Stable
+ *
+ * These functions are used in client code to conditionalize compilation
+ * depending on the version of libdnf headers installed.
+ */
+
+#ifndef __DNF_VERSION_H
+#define __DNF_VERSION_H
+
+/* compile time version
+ */
+#define LIBDNF_MAJOR_VERSION (@LIBDNF_MAJOR_VERSION@)
+#define LIBDNF_MINOR_VERSION (@LIBDNF_MINOR_VERSION@)
+#define LIBDNF_MICRO_VERSION (@LIBDNF_MICRO_VERSION@)
+#define LIBDNF_VERSION "@LIBDNF_VERSION@"
+
+/* check whether a As version equal to or greater than
+ * major.minor.micro.
+ */
+#define DNF_CHECK_VERSION(major,minor,micro) \
+ (LIBDNF_MAJOR_VERSION > (major) || \
+ (LIBDNF_MAJOR_VERSION == (major) && LIBDNF_MINOR_VERSION > (minor)) || \
+ (LIBDNF_MAJOR_VERSION == (major) && LIBDNF_MINOR_VERSION == (minor) && \
+ LIBDNF_MICRO_VERSION >= (micro)))
+
+#endif /* __DNF_VERSION_H */
--- /dev/null
+#ifndef LIBDNF_ERROR_HPP
+#define LIBDNF_ERROR_HPP
+
+#include <stdexcept>
+
+
+namespace libdnf {
+
+/**
+ * A class to use or inherit from for all errors that are expected to happen
+ * (e.g. file not found, permissions, a failed HTTP request, even a corrupted
+ * SQLite database).
+ */
+class Error : public std::runtime_error {
+public:
+ using runtime_error::runtime_error;
+};
+
+/**
+ * An unexpected error (that is, really an exception), for errors that
+ * shouldn't occur. Similar in semantics to an assert error, or
+ * std::logic_error (which is misused in the standard library and e.g.
+ * std::stoi throws it as the std::invalid_argument error, which is an error
+ * that can occur under regular circumstances).
+ *
+ * By decision we do not catch these exceptions as of now. By not catching it,
+ * a terminate() is called and a traceback can be retrieved, which is not the
+ * case when the exception is caught. Since these are an unexpected state, a
+ * crash is an acceptable outcome and having the traceback is important for
+ * debugging the issue.
+ *
+ * Therefore, Exception is unrelated to Error (neither inherits from the other).
+ */
+class Exception : public std::runtime_error {
+public:
+ using runtime_error::runtime_error;
+};
+
+} // namespace libdnf
+
+#endif
--- /dev/null
+set(GOAL_SOURCES
+ ${GOAL_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Goal.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GOAL_PRIVATE_HPP
+#define __GOAL_PRIVATE_HPP
+
+#include "Goal.hpp"
+#include "IdQueue.hpp"
+#include "../sack/packageset.hpp"
+
+namespace libdnf {
+
+class Goal::Impl {
+public:
+ Impl(DnfSack * sack);
+ Impl(const Goal::Impl & src_goal);
+ ~Impl();
+private:
+ friend Goal;
+ friend Query;
+
+ DnfSack *sack;
+ Queue staging;
+ PackageSet exclude_from_weak;
+ Solver *solv{nullptr};
+ ::Transaction *trans{nullptr};
+ DnfGoalActions actions{DNF_NONE};
+ std::unique_ptr<PackageSet> protectedPkgs;
+ bool protect_running_kernel{true};
+ std::unique_ptr<PackageSet> removalOfProtected;
+
+ PackageSet listResults(Id type_filter1, Id type_filter2);
+ void allowUninstallAllButProtected(Queue *job, DnfGoalActions flags);
+ std::unique_ptr<IdQueue> constructJob(DnfGoalActions flags);
+ bool solve(Queue *job, DnfGoalActions flags);
+ Solver * initSolver();
+ int limitInstallonlyPackages(Solver *solv, Queue *job);
+ std::unique_ptr<IdQueue> conflictPkgs(unsigned i);
+ std::unique_ptr<IdQueue> brokenDependencyPkgs(unsigned i);
+ Id protectedRunningKernel();
+ bool protectedInRemovals();
+ std::string describeProtectedRemoval();
+ std::unique_ptr<PackageSet> brokenDependencyAllPkgs(DnfPackageState pkg_type);
+ int countProblems();
+ bool isBrokenFileDependencyPresent();
+ bool isBrokenFileDependencyPresent(unsigned i);
+};
+
+}
+
+#endif /* __GOAL_PRIVATE_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <map>
+#include <vector>
+#include <numeric>
+
+extern "C" {
+#include <solv/evr.h>
+#include <solv/queue.h>
+#include <solv/selection.h>
+#include <solv/solver.h>
+#include <solv/solverdebug.h>
+#include <solv/testcase.h>
+#include <solv/transaction.h>
+#include <solv/rules.h>
+}
+
+#include "Goal-private.hpp"
+#include "../hy-goal-private.hpp"
+#include "../hy-iutil-private.hpp"
+#include "../hy-package-private.hpp"
+#include "../dnf-sack-private.hpp"
+#include "../sack/packageset.hpp"
+#include "../sack/query.hpp"
+#include "../sack/selector.hpp"
+#include "../utils/bgettext/bgettext-lib.h"
+#include "../utils/tinyformat/tinyformat.hpp"
+#include "IdQueue.hpp"
+#include "../utils/filesystem.hpp"
+
+namespace {
+
+std::string pkgSolvid2str(Pool * pool, Id source)
+{
+ return pool_solvid2str(pool, source);
+}
+
+std::string moduleSolvid2str(Pool * pool, Id source)
+{
+ std::ostringstream ss;
+ auto * solvable = pool_id2solvable(pool, source);
+ // Add name:stream
+ ss << solvable_lookup_str(solvable, SOLVABLE_DESCRIPTION);
+ //Add version
+ ss << ":" << pool_id2str(pool, solvable->evr);
+ // Add original context
+ ss << ":" << solvable_lookup_str(solvable, SOLVABLE_SUMMARY);
+ ss << "." << pool_id2str(pool, solvable->arch);
+ return ss.str();
+}
+
+}
+
+namespace libdnf {
+
+enum {NO_MATCH=1, MULTIPLE_MATCH_OBJECTS, INCORECT_COMPARISON_TYPE};
+
+static std::map<int, const char *> ERROR_DICT = {
+ {MULTIPLE_MATCH_OBJECTS, M_("Ill-formed Selector, presence of multiple match objects in the filter")},
+ {INCORECT_COMPARISON_TYPE, M_("Ill-formed Selector used for the operation, incorrect comparison type")}
+};
+
+enum {RULE_DISTUPGRADE=1, RULE_INFARCH, RULE_UPDATE, RULE_JOB, RULE_JOB_UNSUPPORTED, RULE_JOB_NOTHING_PROVIDES_DEP,
+ RULE_JOB_UNKNOWN_PACKAGE, RULE_JOB_PROVIDED_BY_SYSTEM, RULE_PKG, RULE_BEST_1, RULE_BEST_2,
+ RULE_PKG_NOT_INSTALLABLE_1, RULE_PKG_NOT_INSTALLABLE_2, RULE_PKG_NOT_INSTALLABLE_3, RULE_PKG_NOT_INSTALLABLE_4, RULE_PKG_NOTHING_PROVIDES_DEP,
+ RULE_PKG_SAME_NAME, RULE_PKG_CONFLICTS, RULE_PKG_OBSOLETES, RULE_PKG_INSTALLED_OBSOLETES, RULE_PKG_IMPLICIT_OBSOLETES,
+ RULE_PKG_REQUIRES, RULE_PKG_SELF_CONFLICT, RULE_YUMOBS
+};
+
+static const std::map<int, const char *> PKG_PROBLEMS_DICT = {
+ {RULE_DISTUPGRADE, M_("%s from %s does not belong to a distupgrade repository")},
+ {RULE_INFARCH, M_("%s from %s has inferior architecture")},
+ {RULE_UPDATE, M_("problem with installed package ")},
+ {RULE_JOB, M_("conflicting requests")},
+ {RULE_JOB_UNSUPPORTED, M_("unsupported request")},
+ {RULE_JOB_NOTHING_PROVIDES_DEP, M_("nothing provides requested ")},
+ {RULE_JOB_UNKNOWN_PACKAGE, M_("package %s does not exist")},
+ {RULE_JOB_PROVIDED_BY_SYSTEM, M_(" is provided by the system")},
+ {RULE_PKG, M_("some dependency problem")},
+ {RULE_BEST_1, M_("cannot install the best update candidate for package ")},
+ {RULE_BEST_2, M_("cannot install the best candidate for the job")},
+ {RULE_PKG_NOT_INSTALLABLE_1, M_("package %s from %s is filtered out by modular filtering")},
+ {RULE_PKG_NOT_INSTALLABLE_2, M_("package %s from %s does not have a compatible architecture")},
+ {RULE_PKG_NOT_INSTALLABLE_3, M_("package %s from %s is not installable")},
+ {RULE_PKG_NOT_INSTALLABLE_4, M_("package %s from %s is filtered out by exclude filtering")},
+ {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by %s from %s")},
+ {RULE_PKG_SAME_NAME, M_("cannot install both %s from %s and %s from %s")},
+ {RULE_PKG_CONFLICTS, M_("package %s from %s conflicts with %s provided by %s from %s")},
+ {RULE_PKG_OBSOLETES, M_("package %s from %s obsoletes %s provided by %s from %s")},
+ {RULE_PKG_INSTALLED_OBSOLETES, M_("installed package %s obsoletes %s provided by %s from %s")},
+ {RULE_PKG_IMPLICIT_OBSOLETES, M_("package %s from %s implicitly obsoletes %s provided by %s from %s")},
+ {RULE_PKG_REQUIRES, M_("package %s from %s requires %s, but none of the providers can be installed")},
+ {RULE_PKG_SELF_CONFLICT, M_("package %s from %s conflicts with %s provided by itself")},
+ {RULE_YUMOBS, M_("both package %s from %s and %s from %s obsolete %s")}
+};
+
+static const std::map<int, const char *> MODULE_PROBLEMS_DICT = {
+ {RULE_DISTUPGRADE, M_("%s from %s does not belong to a distupgrade repository")},
+ {RULE_INFARCH, M_("%s from %s has inferior architecture")},
+ {RULE_UPDATE, M_("problem with installed module ")},
+ {RULE_JOB, M_("conflicting requests")},
+ {RULE_JOB_UNSUPPORTED, M_("unsupported request")},
+ {RULE_JOB_NOTHING_PROVIDES_DEP, M_("nothing provides requested ")},
+ {RULE_JOB_UNKNOWN_PACKAGE, M_("module %s does not exist")},
+ {RULE_JOB_PROVIDED_BY_SYSTEM, M_(" is provided by the system")},
+ {RULE_PKG, M_("some dependency problem")},
+ {RULE_BEST_1, M_("cannot install the best update candidate for module ")},
+ {RULE_BEST_2, M_("cannot install the best candidate for the job")},
+ {RULE_PKG_NOT_INSTALLABLE_1, M_("module %s from %s is disabled")},
+ {RULE_PKG_NOT_INSTALLABLE_2, M_("module %s from %s does not have a compatible architecture")},
+ {RULE_PKG_NOT_INSTALLABLE_3, M_("module %s from %s is not installable")},
+ {RULE_PKG_NOT_INSTALLABLE_4, M_("module %s from %s is disabled")},
+ {RULE_PKG_NOTHING_PROVIDES_DEP, M_("nothing provides %s needed by module %s from %s")},
+ {RULE_PKG_SAME_NAME, M_("cannot install both modules %s from %s and %s from %s")},
+ {RULE_PKG_CONFLICTS, M_("module %s from %s conflicts with %s provided by %s from %s")},
+ {RULE_PKG_OBSOLETES, M_("module %s from %s obsoletes %s provided by %s from %s")},
+ {RULE_PKG_INSTALLED_OBSOLETES, M_("installed module %s obsoletes %s provided by %s from %s")},
+ {RULE_PKG_IMPLICIT_OBSOLETES, M_("module %s from %s implicitly obsoletes %s provided by %s from %s")},
+ {RULE_PKG_REQUIRES, M_("module %s from %s requires %s, but none of the providers can be installed")},
+ {RULE_PKG_SELF_CONFLICT, M_("module %s from %s conflicts with %s provided by itself")},
+ {RULE_YUMOBS, M_("both module %s from %s and %s from %s obsolete %s")}
+};
+
+static std::string
+libdnf_problemruleinfo2str(libdnf::PackageSet * modularExclude, Solver *solv, SolverRuleinfo type, Id source, Id target,
+ Id dep, bool pkgs)
+{
+ const std::map<int, const char *> & problemDict = pkgs ? PKG_PROBLEMS_DICT : MODULE_PROBLEMS_DICT;
+ const auto solvid2str = pkgs ? pkgSolvid2str : moduleSolvid2str;
+
+ Pool * const pool = solv->pool;
+ Solvable *ss;
+ switch (type) {
+ case SOLVER_RULE_DISTUPGRADE:
+ return tfm::format(TM_(problemDict.at(RULE_DISTUPGRADE), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name);
+ case SOLVER_RULE_INFARCH:
+ return tfm::format(TM_(problemDict.at(RULE_DISTUPGRADE), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name);
+ case SOLVER_RULE_UPDATE:
+ return std::string(TM_(problemDict.at(RULE_UPDATE), 1)) + solvid2str(pool, source);
+ case SOLVER_RULE_JOB:
+ return std::string(TM_(problemDict.at(RULE_JOB), 1));
+ case SOLVER_RULE_JOB_UNSUPPORTED:
+ return std::string(TM_(problemDict.at(RULE_JOB_UNSUPPORTED), 1));
+ case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
+ return std::string(TM_(problemDict.at(RULE_JOB_NOTHING_PROVIDES_DEP), 1)) + pool_dep2str(pool, dep);
+ case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
+ return tfm::format(TM_(problemDict.at(RULE_JOB_UNKNOWN_PACKAGE), 1), pool_dep2str(pool, dep));
+ case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
+ return std::string(pool_dep2str(pool, dep)) + TM_(problemDict.at(RULE_JOB_PROVIDED_BY_SYSTEM), 1);
+ case SOLVER_RULE_PKG:
+ return std::string(TM_(problemDict.at(RULE_PKG), 1));
+ case SOLVER_RULE_BEST:
+ if (source > 0)
+ return std::string(TM_(problemDict.at(RULE_BEST_1), 1)) + solvid2str(pool, source);
+ return std::string(TM_(problemDict.at(RULE_BEST_2), 1));
+ case SOLVER_RULE_PKG_NOT_INSTALLABLE:
+ ss = pool->solvables + source;
+ if (pool_disabled_solvable(pool, ss)) {
+ if (modularExclude && modularExclude->has(source)) {
+ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_1), 1),
+ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name);
+ } else {
+ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_4), 1),
+ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name);
+ }
+ }
+ if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC &&
+ pool->id2arch && (ss->arch > pool->lastarch || !pool->id2arch[ss->arch]))
+ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_2), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name);
+ return tfm::format(TM_(problemDict.at(RULE_PKG_NOT_INSTALLABLE_3), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name);
+ case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_NOTHING_PROVIDES_DEP), 1), pool_dep2str(pool, dep),
+ solvid2str(pool, source).c_str(), pool_id2solvable(pool, source)->repo->name);
+ case SOLVER_RULE_PKG_SAME_NAME:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_SAME_NAME), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(),
+ pool_id2solvable(pool, target)->repo->name);
+ case SOLVER_RULE_PKG_CONFLICTS:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_CONFLICTS), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep),
+ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name);
+ case SOLVER_RULE_PKG_OBSOLETES:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_OBSOLETES), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep),
+ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name);
+ case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_INSTALLED_OBSOLETES), 1),
+ solvid2str(pool, source).c_str(), pool_dep2str(pool, dep),
+ solvid2str(pool, target).c_str(), pool_id2solvable(pool, target)->repo->name);
+ case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_IMPLICIT_OBSOLETES), 1),
+ solvid2str(pool, source).c_str(), pool_dep2str(pool, dep),
+ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(),
+ pool_id2solvable(pool, target)->repo->name);
+ case SOLVER_RULE_PKG_REQUIRES:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_REQUIRES), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep));
+ case SOLVER_RULE_PKG_SELF_CONFLICT:
+ return tfm::format(TM_(problemDict.at(RULE_PKG_SELF_CONFLICT), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, pool_dep2str(pool, dep));
+ case SOLVER_RULE_YUMOBS:
+ return tfm::format(TM_(problemDict.at(RULE_YUMOBS), 1), solvid2str(pool, source).c_str(),
+ pool_id2solvable(pool, source)->repo->name, solvid2str(pool, target).c_str(),
+ pool_id2solvable(pool, target)->repo->name, pool_dep2str(pool, dep));
+ default:
+ return solver_problemruleinfo2str(solv, type, source, target, dep);
+ }
+}
+
+static void
+packageToJob(DnfPackage * package, Queue * job, int solver_action)
+{
+ IdQueue pkgs;
+
+ Pool *pool = dnf_package_get_pool(package);
+ DnfSack *sack = dnf_package_get_sack(package);
+
+ dnf_sack_recompute_considered(sack);
+ dnf_sack_make_provides_ready(sack);
+
+ pkgs.pushBack(dnf_package_get_id(package));
+
+ Id what = pool_queuetowhatprovides(pool, pkgs.getQueue());
+ queue_push2(job, SOLVER_SOLVABLE_ONE_OF|SOLVER_SETARCH|SOLVER_SETEVR|solver_action, what);
+}
+
+static int
+jobHas(Queue *job, Id what, Id id)
+{
+ for (int i = 0; i < job->count; i += 2)
+ if (job->elements[i] == what && job->elements[i + 1] == id)
+ return 1;
+ return 0;
+}
+
+static int
+filterArchToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ if (!f)
+ return 0;
+
+ auto matches = f->getMatches();
+
+ if (f->getCmpType() != HY_EQ) {
+ return INCORECT_COMPARISON_TYPE;
+ }
+ if (matches.size() != 1) {
+ return MULTIPLE_MATCH_OBJECTS;
+ }
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char *arch = matches[0].str;
+ Id archid = str2archid(pool, arch);
+
+ if (archid == 0)
+ return NO_MATCH;
+ for (int i = 0; i < job->count; i += 2) {
+ Id dep;
+ assert((job->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME);
+ dep = pool_rel2id(pool, job->elements[i + 1],
+ archid, REL_ARCH, 1);
+ job->elements[i] |= SOLVER_SETARCH;
+ job->elements[i + 1] = dep;
+ }
+ return 0;
+}
+
+static int
+filterEvrToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ if (!f)
+ return 0;
+ auto matches = f->getMatches();
+
+ if (f->getCmpType() != HY_EQ) {
+ return INCORECT_COMPARISON_TYPE;
+ }
+ if (matches.size() != 1) {
+ return MULTIPLE_MATCH_OBJECTS;
+ }
+
+ Pool *pool = dnf_sack_get_pool(sack);
+ Id evr = pool_str2id(pool, matches[0].str, 1);
+ Id constr = f->getKeyname() == HY_PKG_VERSION ? SOLVER_SETEV : SOLVER_SETEVR;
+ for (int i = 0; i < job->count; i += 2) {
+ Id dep;
+ assert((job->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME);
+ dep = pool_rel2id(pool, job->elements[i + 1],
+ evr, REL_EQ, 1);
+ job->elements[i] |= constr;
+ job->elements[i + 1] = dep;
+ }
+ return 0;
+}
+
+static int
+filterFileToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ if (!f)
+ return 0;
+
+ auto matches = f->getMatches();
+
+ if (matches.size() != 1) {
+ return MULTIPLE_MATCH_OBJECTS;
+ }
+
+ const char *file = matches[0].str;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ int flags = f->getCmpType() & HY_GLOB ? SELECTION_GLOB : 0;
+ if (f->getCmpType() & HY_GLOB)
+ flags |= SELECTION_NOCASE;
+ if (selection_make(pool, job, file, flags | SELECTION_FILELIST) == 0)
+ return NO_MATCH;
+ return 0;
+}
+
+static int
+filterPkgToJob(Id what, Queue *job)
+{
+ if (!what)
+ return 0;
+ queue_push2(job, SOLVER_SOLVABLE_ONE_OF|SOLVER_SETARCH|SOLVER_SETEVR, what);
+ return 0;
+}
+
+static int
+filterNameToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ if (!f)
+ return 0;
+ if (f->getMatches().size() != 1)
+ return MULTIPLE_MATCH_OBJECTS;
+
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char *name = f->getMatches()[0].str;
+ Id id;
+ Dataiterator di;
+
+ switch (f->getCmpType()) {
+ case HY_EQ:
+ id = pool_str2id(pool, name, 0);
+ if (id)
+ queue_push2(job, SOLVER_SOLVABLE_NAME, id);
+ break;
+ case HY_GLOB:
+ dataiterator_init(&di, pool, 0, 0, SOLVABLE_NAME, name, SEARCH_GLOB);
+ while (dataiterator_step(&di)) {
+ if (!is_package(pool, pool_id2solvable(pool, di.solvid)))
+ continue;
+ assert(di.idp);
+ id = *di.idp;
+ if (jobHas(job, SOLVABLE_NAME, id))
+ continue;
+ queue_push2(job, SOLVER_SOLVABLE_NAME, id);
+ }
+ dataiterator_free(&di);
+ break;
+ default:
+ return INCORECT_COMPARISON_TYPE;
+ }
+ return 0;
+}
+
+static int
+filterProvidesToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ if (!f)
+ return 0;
+ auto matches = f->getMatches();
+ if (f->getMatches().size() != 1)
+ return MULTIPLE_MATCH_OBJECTS;
+ const char *name;
+ Pool *pool = dnf_sack_get_pool(sack);
+ Id id;
+ Dataiterator di;
+
+ switch (f->getCmpType()) {
+ case HY_EQ:
+ id = matches[0].reldep;
+ queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
+ break;
+ case HY_GLOB:
+ name = matches[0].str;
+ dataiterator_init(&di, pool, 0, 0, SOLVABLE_PROVIDES, name, SEARCH_GLOB);
+ while (dataiterator_step(&di)) {
+ if (is_package(pool, pool_id2solvable(pool, di.solvid)))
+ break;
+ }
+ assert(di.idp);
+ id = *di.idp;
+ if (!jobHas(job, SOLVABLE_PROVIDES, id))
+ queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
+ dataiterator_free(&di);
+ break;
+ default:
+ return INCORECT_COMPARISON_TYPE;
+ }
+ return 0;
+}
+
+static int
+filterReponameToJob(DnfSack *sack, const Filter *f, Queue *job)
+{
+ Id i;
+ LibsolvRepo *repo;
+
+ if (!f)
+ return 0;
+ auto matches = f->getMatches();
+
+ if (f->getCmpType() != HY_EQ) {
+ return INCORECT_COMPARISON_TYPE;
+ }
+ if (matches.size() != 1) {
+ return MULTIPLE_MATCH_OBJECTS;
+ }
+
+ IdQueue repo_sel;
+ Pool *pool = dnf_sack_get_pool(sack);
+ FOR_REPOS(i, repo)
+ if (!strcmp(matches[0].str, repo->name)) {
+ repo_sel.pushBack(SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, repo->repoid);
+ }
+
+ selection_filter(pool, job, repo_sel.getQueue());
+
+ return 0;
+}
+
+/**
+ * Build job queue from a Query.
+ *
+ * Returns an error code
+ */
+void
+sltrToJob(const HySelector sltr, Queue *job, int solver_action)
+{
+ DnfSack *sack = sltr->getSack();
+ int ret = 0;
+
+ int any_opt_filter = sltr->getFilterArch() || sltr->getFilterEvr()
+ || sltr->getFilterReponame();
+ int any_req_filter = sltr->getFilterName() || sltr->getFilterProvides()
+ || sltr->getFilterFile() || sltr->getPkgs();
+
+ IdQueue job_sltr;
+
+ if (!any_req_filter) {
+ if (any_opt_filter) {
+ // no name or provides or file in the selector is an error
+ throw Goal::Error("Ill-formed Selector. No name or"
+ "provides or file in the selector.", DNF_ERROR_BAD_SELECTOR);
+ }
+ goto finish;
+ }
+
+ dnf_sack_recompute_considered(sack);
+ dnf_sack_make_provides_ready(sack);
+ ret = filterPkgToJob(sltr->getPkgs(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterNameToJob(sack, sltr->getFilterName(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterFileToJob(sack, sltr->getFilterFile(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterProvidesToJob(sack, sltr->getFilterProvides(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterArchToJob(sack, sltr->getFilterArch(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterEvrToJob(sack, sltr->getFilterEvr(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+ ret = filterReponameToJob(sack, sltr->getFilterReponame(), job_sltr.getQueue());
+ if (ret)
+ goto finish;
+
+ for (int i = 0; i < job_sltr.size(); i += 2)
+ queue_push2(job, job_sltr[i] | solver_action, job_sltr[i + 1]);
+
+ finish:
+ if (ret > 1) {
+ throw Goal::Error(TM_(ERROR_DICT[ret], 1), DNF_ERROR_BAD_SELECTOR);
+ }
+}
+
+#define BLOCK_SIZE 15
+
+struct InstallonliesSortCallback {
+ Pool *pool;
+ Id running_kernel;
+};
+
+static inline void
+queue2pset(const IdQueue & queue, PackageSet * pset)
+{
+ for (int i = 0; i < queue.size(); ++i)
+ pset->set(queue[i]);
+}
+
+static bool
+/**
+* @brief return false iff a does not depend on anything from b
+*/
+can_depend_on(Pool *pool, Solvable *sa, Id b)
+{
+ IdQueue dep_requires;
+
+ solvable_lookup_idarray(sa, SOLVABLE_REQUIRES, dep_requires.getQueue());
+ for (int i = 0; i < dep_requires.size(); ++i) {
+ Id req_dep = dep_requires[i];
+ Id p, pp;
+
+ FOR_PROVIDES(p, pp, req_dep)
+ if (p == b)
+ return true;
+ }
+
+ return false;
+}
+
+static int
+sort_packages(const void *ap, const void *bp, void *s_cb)
+{
+ Id a = *(Id*)ap;
+ Id b = *(Id*)bp;
+ Pool *pool = ((struct InstallonliesSortCallback*) s_cb)->pool;
+ Id kernel = ((struct InstallonliesSortCallback*) s_cb)->running_kernel;
+ Solvable *sa = pool_id2solvable(pool, a);
+ Solvable *sb = pool_id2solvable(pool, b);
+
+ /* if the names are different sort them differently, particular order does
+ not matter as long as it's consistent. */
+ int name_diff = sa->name - sb->name;
+ if (name_diff)
+ return name_diff;
+
+ /* same name, if one is/depends on the running kernel put it last */
+
+ /* move available packages to end of the list */
+ if (pool->installed != sa->repo)
+ return 1;
+
+ if (pool->installed != sb->repo)
+ return -1;
+
+ if (kernel >= 0) {
+ if (a == kernel || can_depend_on(pool, sa, kernel))
+ return 1;
+ if (b == kernel || can_depend_on(pool, sb, kernel))
+ return -1;
+ // if package has same evr as kernel try them to keep (kernel-devel packages)
+ Solvable * kernelSolvable = pool_id2solvable(pool, kernel);
+ if (sa->evr == kernelSolvable->evr) {
+ return 1;
+ }
+ if (sb->evr == kernelSolvable->evr) {
+ return -1;
+ }
+ }
+ return pool_evrcmp(pool, sa->evr, sb->evr, EVRCMP_COMPARE);
+}
+
+static void
+same_name_subqueue(Pool *pool, Queue *in, Queue *out)
+{
+ Id el = queue_pop(in);
+ Id name = pool_id2solvable(pool, el)->name;
+ queue_empty(out);
+ queue_push(out, el);
+ while (in->count &&
+ pool_id2solvable(pool, in->elements[in->count - 1])->name == name)
+ // reverses the order so packages are sorted by descending version
+ queue_push(out, queue_pop(in));
+}
+
+static std::unique_ptr<PackageSet>
+remove_pkgs_with_same_nevra_from_pset(DnfPackageSet* pset, DnfPackageSet* remove_musters,
+ DnfSack* sack)
+{
+ std::unique_ptr<PackageSet> final_pset(new PackageSet(sack));
+ Id id1 = -1;
+ while(true) {
+ id1 = pset->next(id1);
+ if (id1 == -1)
+ break;
+ DnfPackage *pkg1 = dnf_package_new(sack, id1);
+ Id id2 = -1;
+ bool found = false;
+ while(true) {
+ id2 = remove_musters->next(id2);
+ if (id2 == -1)
+ break;
+ DnfPackage *pkg2 = dnf_package_new(sack, id2);
+ if (!dnf_package_cmp(pkg1, pkg2)) {
+ found = true;
+ g_object_unref(pkg2);
+ break;
+ }
+ g_object_unref(pkg2);
+ }
+ if (!found) {
+ final_pset->set(pkg1);
+ }
+ g_object_unref(pkg1);
+ }
+ return final_pset;
+}
+
+static int
+erase_flags2libsolv(int flags)
+{
+ int ret = 0;
+ if (flags & HY_CLEAN_DEPS)
+ ret |= SOLVER_CLEANDEPS;
+ return ret;
+}
+
+static bool
+NameSolvableComparator(const Solvable * first, const Solvable * second)
+{
+ return first->name < second->name;
+}
+
+Goal::Goal(const Goal & goal_src) : pImpl(new Impl(*goal_src.pImpl)) {}
+
+Goal::Impl::Impl(const Goal::Impl & goal_src)
+: sack(goal_src.sack), exclude_from_weak(goal_src.exclude_from_weak)
+{
+ queue_init_clone(&staging, const_cast<Queue *>(&goal_src.staging));
+
+ actions = goal_src.actions;
+ if (goal_src.protectedPkgs) {
+ protectedPkgs.reset(new PackageSet(*goal_src.protectedPkgs.get()));
+ }
+ if (goal_src.removalOfProtected) {
+ removalOfProtected.reset(new PackageSet(*goal_src.removalOfProtected.get()));
+ }
+}
+
+Goal::Impl::Impl(DnfSack *sack)
+: sack(sack), exclude_from_weak(sack)
+{
+ queue_init(&staging);
+}
+
+Goal::Goal(DnfSack *sack) : pImpl(new Impl(sack)) {}
+
+Goal::~Goal() = default;
+
+Goal::Impl::~Impl()
+{
+ if (trans)
+ transaction_free(trans);
+ if (solv)
+ solver_free(solv);
+ queue_free(&staging);
+}
+
+DnfGoalActions Goal::getActions() { return pImpl->actions; }
+
+DnfSack * Goal::getSack() { return pImpl->sack; }
+
+int
+Goal::getReason(DnfPackage *pkg)
+{
+ //solver_get_recommendations
+ if (!pImpl->solv)
+ return HY_REASON_USER;
+ Id info;
+ const Id pkgID = dnf_package_get_id(pkg);
+ int reason = solver_describe_decision(pImpl->solv, pkgID, &info);
+
+ if ((reason == SOLVER_REASON_UNIT_RULE ||
+ reason == SOLVER_REASON_RESOLVE_JOB) &&
+ (solver_ruleclass(pImpl->solv, info) == SOLVER_RULE_JOB ||
+ solver_ruleclass(pImpl->solv, info) == SOLVER_RULE_BEST))
+ return HY_REASON_USER;
+ if (reason == SOLVER_REASON_CLEANDEPS_ERASE)
+ return HY_REASON_CLEAN;
+ if (reason == SOLVER_REASON_WEAKDEP)
+ return HY_REASON_WEAKDEP;
+ IdQueue cleanDepsQueue;
+ solver_get_cleandeps(pImpl->solv, cleanDepsQueue.getQueue());
+ for (int i = 0; i < cleanDepsQueue.size(); ++i) {
+ if (cleanDepsQueue[i] == pkgID) {
+ return HY_REASON_CLEAN;
+ }
+ }
+ return HY_REASON_DEP;
+}
+
+void
+Goal::addProtected(PackageSet & pset)
+{
+ if (!pImpl->protectedPkgs) {
+ pImpl->protectedPkgs.reset(new PackageSet(pset));
+ } else {
+ map_or(pImpl->protectedPkgs->getMap(), pset.getMap());
+ }
+}
+
+bool
+Goal::get_protect_running_kernel() const noexcept
+{
+ return pImpl->protect_running_kernel;
+}
+
+void
+Goal::set_protect_running_kernel(bool value)
+{
+ pImpl->protect_running_kernel = value;
+}
+
+void
+Goal::setProtected(const PackageSet & pset)
+{
+ pImpl->protectedPkgs.reset(new PackageSet(pset));
+}
+
+void
+Goal::distupgrade()
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_DISTUPGRADE|DNF_ALLOW_DOWNGRADE);
+ DnfSack * sack = pImpl->sack;
+ Query query(sack);
+ query.available();
+ Selector selector(sack);
+ selector.set(query.runSet());
+ sltrToJob(&selector, &pImpl->staging, SOLVER_DISTUPGRADE);
+}
+
+void
+Goal::distupgrade(DnfPackage *new_pkg)
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_DISTUPGRADE|DNF_ALLOW_DOWNGRADE);
+ packageToJob(new_pkg, &pImpl->staging, SOLVER_DISTUPGRADE);
+}
+
+void
+Goal::distupgrade(HySelector sltr)
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_DISTUPGRADE|DNF_ALLOW_DOWNGRADE);
+ sltrToJob(sltr, &pImpl->staging, SOLVER_DISTUPGRADE);
+}
+
+void
+Goal::erase(DnfPackage *pkg, int flags)
+{
+ int additional = erase_flags2libsolv(flags);
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_ERASE);
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_ERASE|additional, dnf_package_get_id(pkg));
+}
+
+void
+Goal::erase(HySelector sltr, int flags)
+{
+ int additional = erase_flags2libsolv(flags);
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_ERASE);
+ sltrToJob(sltr, &pImpl->staging, SOLVER_ERASE|additional);
+}
+
+void
+Goal::install(DnfPackage *new_pkg, bool optional)
+{
+ int solverActions = SOLVER_INSTALL;
+ if (optional) {
+ solverActions |= SOLVER_WEAK;
+ }
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_INSTALL|DNF_ALLOW_DOWNGRADE);
+ packageToJob(new_pkg, &pImpl->staging, solverActions);
+}
+
+void
+Goal::lock(DnfPackage *pkg)
+{
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_LOCK, dnf_package_get_id(pkg));
+}
+
+void
+Goal::favor(DnfPackage *pkg)
+{
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_FAVOR, dnf_package_get_id(pkg));
+}
+
+void
+Goal::add_exclude_from_weak(const DnfPackageSet & pset)
+{
+ pImpl->exclude_from_weak += pset;
+}
+
+void
+Goal::add_exclude_from_weak(DnfPackage *pkg)
+{
+ // ensure that the map has a corrent size before set to prevent memory corruption
+ map_grow(pImpl->exclude_from_weak.getMap(), dnf_sack_get_pool(pImpl->sack)->nsolvables);
+ pImpl->exclude_from_weak.set(pkg);
+}
+
+void
+Goal::reset_exclude_from_weak()
+{
+ pImpl->exclude_from_weak.clear();
+}
+
+void
+Goal::exclude_from_weak_autodetect()
+{
+ Query installed_query(pImpl->sack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ installed_query.installed();
+ if (installed_query.empty()) {
+ return;
+ }
+ Query base_query(pImpl->sack);
+ base_query.apply();
+ auto * installed_pset = installed_query.getResultPset();
+ Id installed_id = -1;
+
+ std::vector<const char *> installed_names;
+ installed_names.reserve(installed_pset->size() + 1);
+
+ // Iterate over installed packages to detect unmet weak deps
+ while ((installed_id = installed_pset->next(installed_id)) != -1) {
+ g_autoptr(DnfPackage) pkg = dnf_package_new(pImpl->sack, installed_id);
+ installed_names.push_back(dnf_package_get_name(pkg));
+ std::unique_ptr<libdnf::DependencyContainer> recommends(dnf_package_get_recommends(pkg));
+ for (int i = 0; i < recommends->count(); ++i) {
+ std::unique_ptr<libdnf::Dependency> dep(recommends->getPtr(i));
+ const char * dep_string = dep->toString();
+ if (dep_string[0] == '(') {
+ continue;
+ }
+ Query query(base_query);
+ const char * version = dep->getVersion();
+ // There can be installed provider in different version or upgraded packed can recommend a different version
+ // Ignore version and search only by reldep name
+ if (version && strlen(version) > 0) {
+ query.addFilter(HY_PKG_PROVIDES, HY_EQ, dep->getName());
+ } else {
+ query.addFilter(HY_PKG_PROVIDES, dep.get());
+ }
+ // No providers of recommend => continue
+ if (query.empty()) {
+ continue;
+ }
+ Query test_installed(query);
+ test_installed.installed();
+ // when there is not installed any provider of recommend, exclude it
+ if (test_installed.empty()) {
+ add_exclude_from_weak(*query.getResultPset());
+ }
+ }
+ }
+
+ // Investigate supplements of only available packages with a different name to installed packages
+ installed_names.push_back(nullptr);
+ base_query.addFilter(HY_PKG_NAME, HY_NEQ, installed_names.data());
+ auto * available_pset = base_query.getResultPset();
+ *available_pset -= *installed_pset;
+ Id available_id = -1;
+ while ((available_id = available_pset->next(available_id)) != -1) {
+ g_autoptr(DnfPackage) pkg = dnf_package_new(pImpl->sack, available_id);
+ std::unique_ptr<libdnf::DependencyContainer> supplements(dnf_package_get_supplements(pkg));
+ if (supplements->count() == 0) {
+ continue;
+ }
+ libdnf::DependencyContainer supplements_without_rich(getSack());
+ for (int i = 0; i < supplements->count(); ++i) {
+ std::unique_ptr<libdnf::Dependency> dep(supplements->getPtr(i));
+ const char * dep_string = dep->toString();
+ if (dep_string[0] == '(') {
+ continue;
+ }
+ supplements_without_rich.add(dep.get());
+ }
+ if (supplements_without_rich.count() == 0) {
+ continue;
+ }
+ Query query(installed_query);
+ query.addFilter(HY_PKG_PROVIDES, &supplements_without_rich);
+ // When supplemented package already installed, exclude_from_weak available package
+ if (!query.empty()) {
+ add_exclude_from_weak(pkg);
+ }
+ }
+}
+
+void
+Goal::disfavor(DnfPackage *pkg)
+{
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_DISFAVOR, dnf_package_get_id(pkg));
+}
+
+void
+Goal::install(HySelector sltr, bool optional)
+{
+ int solverActions = SOLVER_INSTALL;
+ if (optional) {
+ solverActions |= SOLVER_WEAK;
+ }
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_INSTALL|DNF_ALLOW_DOWNGRADE);
+ sltrToJob(sltr, &pImpl->staging, solverActions);
+}
+
+void
+Goal::upgrade()
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_UPGRADE_ALL);
+ queue_push2(&pImpl->staging, SOLVER_UPDATE|SOLVER_SOLVABLE_ALL, 0);
+}
+
+void
+Goal::upgrade(DnfPackage *new_pkg)
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_UPGRADE);
+ packageToJob(new_pkg, &pImpl->staging, SOLVER_UPDATE);
+}
+
+void
+Goal::upgrade(HySelector sltr)
+{
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | DNF_UPGRADE);
+ auto flags = SOLVER_UPDATE;
+ if (sltr->getPkgs()) {
+ flags |= SOLVER_TARGETED;
+ }
+ sltrToJob(sltr, &pImpl->staging, flags);
+}
+
+void
+Goal::userInstalled(DnfPackage *pkg)
+{
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_USERINSTALLED, dnf_package_get_id(pkg));
+}
+
+void
+Goal::userInstalled(PackageSet & pset)
+{
+ Id id = -1;
+ while (true) {
+ id = pset.next(id);
+ if (id == -1)
+ break;
+ queue_push2(&pImpl->staging, SOLVER_SOLVABLE|SOLVER_USERINSTALLED, id);
+ }
+}
+
+bool
+Goal::hasActions(DnfGoalActions action)
+{
+ return pImpl->actions & action;
+}
+
+int
+Goal::jobLength()
+{
+ return (&pImpl->staging)->count / 2;
+}
+
+bool
+Goal::run(DnfGoalActions flags)
+{
+ auto job = pImpl->constructJob(flags);
+ pImpl->actions = static_cast<DnfGoalActions>(pImpl->actions | flags);
+ int ret = pImpl->solve(job->getQueue(), flags);
+ return ret;
+}
+
+int
+Goal::countProblems()
+{
+ return pImpl->countProblems();
+}
+
+/**
+ * Reports packages that has a conflict
+ *
+ * available - if available it returns set with available packages with conflicts
+ * available - if package installed it also excludes available packages with same NEVRA
+ *
+ * Returns DnfPackageSet with all packages that have a conflict.
+ */
+std::unique_ptr<PackageSet>
+Goal::listConflictPkgs(DnfPackageState pkg_type)
+{
+ DnfSack * sack = pImpl->sack;
+ Pool * pool = dnf_sack_get_pool(sack);
+ std::unique_ptr<PackageSet> pset(new PackageSet(sack));
+ PackageSet temporary_pset(sack);
+
+ int countProblemsValue = pImpl->countProblems();
+ for (int i = 0; i < countProblemsValue; i++) {
+ auto conflict = pImpl->conflictPkgs(i);
+ for (int j = 0; j < conflict->size(); j++) {
+ Id id = (*conflict)[j];
+ Solvable *s = pool_id2solvable(pool, id);
+ bool installed = pool->installed == s->repo;
+ if (pkg_type == DNF_PACKAGE_STATE_AVAILABLE && installed) {
+ temporary_pset.set(id);
+ continue;
+ }
+ if (pkg_type == DNF_PACKAGE_STATE_INSTALLED && !installed)
+ continue;
+ pset->set(id);
+ }
+ }
+ if (!temporary_pset.size()) {
+ return pset;
+ }
+
+ return remove_pkgs_with_same_nevra_from_pset(pset.get(), &temporary_pset, sack);
+}
+
+/**
+ * Reports all packages that have broken dependency
+ * available - if available returns only available packages with broken dependencies
+ * available - if package installed it also excludes available packages with same NEVRA
+ * Returns DnfPackageSet with all packages with broken dependency
+ */
+std::unique_ptr<PackageSet>
+Goal::listBrokenDependencyPkgs(DnfPackageState pkg_type)
+{
+ return pImpl->brokenDependencyAllPkgs(pkg_type);
+}
+
+std::vector<std::vector<std::string>> Goal::describeAllProblemRules(bool pkgs)
+{
+ std::vector<std::vector<std::string>> output;
+ int count_problems = countProblems();
+ for (int i = 0; i < count_problems; i++) {
+ auto problemList = describeProblemRules(i, pkgs);
+ if (problemList.empty()) {
+ continue;
+ }
+ bool unique = true;
+ for (auto & problemsSaved: output) {
+ if (problemList.size() != problemsSaved.size()) {
+ continue;
+ }
+ bool presentElement = false;
+ for (auto & problem: problemList) {
+ presentElement = false;
+ for (auto & problemSaved: problemsSaved) {
+ if (problemSaved == problem) {
+ presentElement = true;
+ break;
+ }
+ }
+ if (!presentElement) {
+ break;
+ }
+ }
+ if (presentElement) {
+ unique = false;
+ }
+ }
+ if (unique) {
+ output.push_back(problemList);
+ }
+ }
+ return output;
+}
+
+std::vector<std::string>
+Goal::describeProblemRules(unsigned i, bool pkgs)
+{
+ std::vector<std::string> output;
+ /* internal error */
+ if (i >= (unsigned) pImpl->countProblems())
+ return output;
+ // problem is not in libsolv - removal of protected packages
+ auto problem = pImpl->describeProtectedRemoval();
+ if (!problem.empty()) {
+ output.push_back(std::move(problem));
+ return output;
+ }
+ auto solv = pImpl->solv;
+
+ Id rid, source, target, dep;
+ SolverRuleinfo type;
+ int j;
+ bool unique;
+
+ if (i >= solver_problem_count(solv))
+ return output;
+
+ IdQueue pq;
+ IdQueue rq;
+ // this libsolv interface indexes from 1 (we do from 0), so:
+ solver_findallproblemrules(solv, i+1, pq.getQueue());
+ std::unique_ptr<libdnf::PackageSet> modularExcludes(dnf_sack_get_module_excludes(pImpl->sack));
+ for (j = 0; j < pq.size(); j++) {
+ rid = pq[j];
+ if (solver_allruleinfos(solv, rid, rq.getQueue())) {
+ for (int ir = 0; ir < rq.size(); ir+=4) {
+ type = static_cast<SolverRuleinfo>(rq[ir]);
+ source = rq[ir + 1];
+ target = rq[ir + 2];
+ dep = rq[ir + 3];
+ auto problem_str = libdnf_problemruleinfo2str(modularExcludes.get(), solv, type,
+ source, target, dep, pkgs);
+ unique = true;
+ for (auto & item: output) {
+ if (problem_str == item) {
+ unique = false;
+ break;
+ }
+ }
+ if (unique) {
+ output.push_back(problem_str);
+ }
+ }
+ }
+ }
+ return output;
+}
+
+bool
+Goal::isBrokenFileDependencyPresent()
+{
+ return pImpl->isBrokenFileDependencyPresent();
+}
+
+bool
+Goal::Impl::isBrokenFileDependencyPresent()
+{
+ for (int i = 0; i < countProblems(); i++) {
+ if (isBrokenFileDependencyPresent(i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Goal::Impl::isBrokenFileDependencyPresent(unsigned i)
+{
+ if (i >= solver_problem_count(solv)) {
+ return false;
+ }
+
+ SolverRuleinfo type;
+ Id source, target, dep;
+ IdQueue pq;
+ Pool * const pool = solv->pool;
+
+ // this libsolv interface indexes from 1 (we do from 0), so:
+ solver_findallproblemrules(solv, i+1, pq.getQueue());
+ for (int j = 0; j < pq.size(); j++) {
+ type = solver_ruleinfo(solv, pq[j], &source, &target, &dep);
+ if (type == SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP) {
+ auto dependency = std::string(pool_dep2str(pool, dep));
+ if (dependency.at(0) == '/') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Write all the solving decisions to the hawkey logfile.
+ */
+int
+Goal::logDecisions()
+{
+ if (!pImpl->solv)
+ return 1;
+ solver_printdecisionq(pImpl->solv, SOLV_DEBUG_RESULT);
+ return 0;
+}
+
+/**
+ * hy_goal_write_debugdata:
+ * @goal: A #HyGoal
+ * @dir: The directory to write to
+ * @error: A #GError, or %NULL
+ *
+ * Writes details about the testcase to a directory.
+ *
+ * Returns: %false if an error was set
+ *
+ * Since: 0.7.0
+ */
+void
+Goal::writeDebugdata(const char *dir)
+{
+ Solver *solv = pImpl->solv;
+ if (!solv) {
+ throw Goal::Error(_("no solver set"), DNF_ERROR_INTERNAL_ERROR);
+ }
+ int flags = TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS;
+ g_autofree char *absdir = abspath(dir);
+ if (!absdir) {
+ std::string msg = tfm::format(_("failed to make %s absolute"), dir);
+ throw Goal::Error(msg, DNF_ERROR_FILE_INVALID);
+ }
+ makeDirPath(dir);
+ g_debug("writing solver debugdata to %s", absdir);
+ int ret = testcase_write(solv, absdir, flags, NULL, NULL);
+ if (!ret) {
+ std::string msg = tfm::format(_("failed writing debugdata to %1$s: %2$s"),
+ absdir, strerror(errno));
+ throw Goal::Error(msg, DNF_ERROR_FILE_INVALID);
+ }
+}
+
+PackageSet
+Goal::Impl::listResults(Id type_filter1, Id type_filter2)
+{
+ /* no transaction */
+ if (!trans) {
+ if (!solv) {
+ throw Goal::Error(_("no solv in the goal"), DNF_ERROR_INTERNAL_ERROR);
+ } else if (removalOfProtected && removalOfProtected->size()) {
+ throw Goal::Error(_("no solution, cannot remove protected package"),
+ DNF_ERROR_REMOVAL_OF_PROTECTED_PKG);
+ }
+ throw Goal::Error(_("no solution possible"), DNF_ERROR_NO_SOLUTION);
+ }
+
+ PackageSet plist(sack);
+ const int common_mode = SOLVER_TRANSACTION_SHOW_OBSOLETES |
+ SOLVER_TRANSACTION_CHANGE_IS_REINSTALL;
+
+ for (int i = 0; i < trans->steps.count; ++i) {
+ Id p = trans->steps.elements[i];
+ Id type;
+
+ switch (type_filter1) {
+ case SOLVER_TRANSACTION_OBSOLETED:
+ type = transaction_type(trans, p, common_mode);
+ break;
+ default:
+ type = transaction_type(trans, p, common_mode |
+ SOLVER_TRANSACTION_SHOW_ACTIVE|
+ SOLVER_TRANSACTION_SHOW_ALL);
+ break;
+ }
+
+ if (type == type_filter1 || (type_filter2 && type == type_filter2))
+ plist.set(p);
+ }
+ return plist;
+}
+
+PackageSet
+Goal::listErasures()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_ERASE, 0);
+}
+
+PackageSet
+Goal::listInstalls()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_INSTALL, SOLVER_TRANSACTION_OBSOLETES);
+}
+
+PackageSet
+Goal::listObsoleted()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_OBSOLETED, 0);
+}
+
+PackageSet
+Goal::listReinstalls()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_REINSTALL, 0);
+}
+
+PackageSet
+Goal::listUnneeded()
+{
+ PackageSet pset(pImpl->sack);
+ IdQueue queue;
+ Solver *solv = pImpl->solv;
+
+ solver_get_unneeded(solv, queue.getQueue(), 0);
+ queue2pset(queue, &pset);
+ return pset;
+}
+
+PackageSet
+Goal::listSuggested()
+{
+ PackageSet pset(pImpl->sack);
+ IdQueue queue;
+ Solver *solv = pImpl->solv;
+
+ solver_get_recommendations(solv, NULL, queue.getQueue(), 0);
+ queue2pset(queue, &pset);
+ return pset;
+}
+
+PackageSet
+Goal::listUpgrades()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_UPGRADE, 0);
+}
+
+PackageSet
+Goal::listDowngrades()
+{
+ return pImpl->listResults(SOLVER_TRANSACTION_DOWNGRADE, 0);
+}
+
+PackageSet
+Goal::listObsoletedByPackage(DnfPackage *pkg)
+{
+ auto trans = pImpl->trans;
+ IdQueue obsoletes;
+ PackageSet pset(pImpl->sack);
+
+ assert(trans);
+
+ transaction_all_obs_pkgs(trans, dnf_package_get_id(pkg), obsoletes.getQueue());
+ queue2pset(obsoletes, &pset);
+
+ return pset;
+}
+
+static std::string string_join(const std::vector<std::string> & src, const std::string & delim)
+{
+ if (src.empty()) {
+ return {};
+ }
+ std::string output(*src.begin());
+ for (auto iter = std::next(src.begin()); iter != src.end(); ++iter) {
+ output.append(delim);
+ output.append(*iter);
+ }
+ return output;
+}
+
+std::string
+Goal::formatAllProblemRules(const std::vector<std::vector<std::string>> & problems)
+{
+ if (problems.empty()) {
+ return {};
+ }
+ bool single_problems = problems.size() == 1;
+ std::string output;
+
+ if (single_problems) {
+ output.append(_("Problem: "));
+ output.append(string_join(*problems.begin(), "\n - "));
+ return output;
+ }
+
+ const char * problem_prefix = _("Problem %d: ");
+
+ output.append(tfm::format(problem_prefix, 1));
+ output.append(string_join(*problems.begin(), "\n - "));
+
+ int index = 2;
+ for (auto iter = std::next(problems.begin()); iter != problems.end(); ++iter) {
+ output.append("\n ");
+ output.append(tfm::format(problem_prefix, index));
+ output.append(string_join(*iter, "\n - "));
+ ++index;
+ }
+ return output;
+}
+
+void
+Goal::Impl::allowUninstallAllButProtected(Queue *job, DnfGoalActions flags)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ if (!protectedPkgs) {
+ protectedPkgs.reset(new PackageSet(sack));
+ } else
+ map_grow(protectedPkgs->getMap(), pool->nsolvables);
+
+ Id protected_kernel = protectedRunningKernel();
+
+ if (DNF_ALLOW_UNINSTALL & flags)
+ for (Id id = 1; id < pool->nsolvables; ++id) {
+ Solvable *s = pool_id2solvable(pool, id);
+ if (pool->installed == s->repo && !protectedPkgs->has(id) &&
+ id != protected_kernel &&
+ (!pool->considered || MAPTST(pool->considered, id))) {
+ queue_push2(job, SOLVER_ALLOWUNINSTALL|SOLVER_SOLVABLE, id);
+ }
+ }
+}
+
+std::unique_ptr<IdQueue>
+Goal::Impl::constructJob(DnfGoalActions flags)
+{
+ std::unique_ptr<IdQueue> job(new IdQueue(staging));
+ auto elements = job->data();
+ /* apply forcebest */
+ if (flags & DNF_FORCE_BEST)
+ for (int i = 0; i < job->size(); i += 2) {
+ elements[i] |= SOLVER_FORCEBEST;
+ }
+
+ // Add weak excludes to the job
+ Id id = -1;
+ while ((id = exclude_from_weak.next(id)) != -1) {
+ job->pushBack(SOLVER_SOLVABLE|SOLVER_EXCLUDEFROMWEAK, id);
+ }
+
+ /* turn off implicit obsoletes for installonly packages */
+ for (int i = 0; i < (int) dnf_sack_get_installonly(sack)->count; i++)
+ job->pushBack(SOLVER_MULTIVERSION|SOLVER_SOLVABLE_PROVIDES,
+ dnf_sack_get_installonly(sack)->elements[i]);
+
+ allowUninstallAllButProtected(job->getQueue(), flags);
+
+ if (flags & DNF_VERIFY)
+ job->pushBack(SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0);
+
+ return job;
+}
+
+Solver *
+Goal::Impl::initSolver()
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solver *solvNew = solver_create(pool);
+
+ if (solv)
+ solver_free(solv);
+ solv = solvNew;
+
+ /* vendor locking */
+ int vendor = dnf_sack_get_allow_vendor_change(sack) ? 1 : 0;
+ solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, vendor);
+ solver_set_flag(solv, SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE, vendor);
+
+ /* don't erase packages that are no longer in repo during distupgrade */
+ solver_set_flag(solv, SOLVER_FLAG_KEEP_ORPHANS, 1);
+ /* no arch change for forcebest */
+ solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+ /* support package splits via obsoletes */
+ solver_set_flag(solv, SOLVER_FLAG_YUM_OBSOLETES, 1);
+
+#if defined(LIBSOLV_FLAG_URPMREORDER)
+ /* support urpm-like solution reordering */
+ solver_set_flag(solv, SOLVER_FLAG_URPM_REORDER, 1);
+#endif
+
+ return solv;
+}
+
+int
+Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
+{
+ if (!dnf_sack_get_installonly_limit(sack))
+ return 0;
+
+ Queue *onlies = dnf_sack_get_installonly(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ int reresolve = 0;
+
+ for (int i = 0; i < onlies->count; ++i) {
+ Id p, pp;
+ IdQueue q, installing;
+ std::vector<Solvable *> available_unused_providers;
+
+ // Add all providers of installonly provides that are marked for install
+ // to `q` IdQueue those that are not marked for install and are not already
+ // installed are added to available_unused_providers.
+ FOR_PKG_PROVIDES(p, pp, onlies->elements[i])
+ // According to libsolv-bindings the decision level is positive for installs
+ // and negative for conflicts (conflicts with another package or dependency
+ // conflicts = dependencies cannot be met).
+ if (solver_get_decisionlevel(solv, p) > 0) {
+ q.pushBack(p);
+ } else {
+ Solvable *s = pool_id2solvable(pool, p);
+ if (s->repo != pool->installed) {
+ available_unused_providers.push_back(s);
+ }
+ }
+
+ if (q.size() <= (int) dnf_sack_get_installonly_limit(sack)) {
+ continue;
+ }
+ for (int k = 0; k < q.size(); ++k) {
+ Id id = q[k];
+ Solvable *s = pool_id2solvable(pool, id);
+ if (pool->installed != s->repo) {
+ installing.pushBack(id);
+ break;
+ }
+ }
+ if (!installing.size()) {
+ continue;
+ }
+
+ struct InstallonliesSortCallback s_cb = {pool, dnf_sack_running_kernel(sack)};
+ solv_sort(q.data(), q.size(), sizeof(q[0]), sort_packages, &s_cb);
+ std::sort(available_unused_providers.begin(), available_unused_providers.end(), NameSolvableComparator);
+ IdQueue same_names;
+ while (q.size() > 0) {
+ same_name_subqueue(pool, q.getQueue(), same_names.getQueue());
+ if (same_names.size() <= (int) dnf_sack_get_installonly_limit(sack))
+ continue;
+ reresolve = 1;
+ for (int j = 0; j < same_names.size(); ++j) {
+ Id id = same_names[j];
+ Id action = SOLVER_ERASE;
+ if (j < (int) dnf_sack_get_installonly_limit(sack)) {
+ action = SOLVER_INSTALL;
+ } else {
+ // We want to avoid reinstalling packages marked for ERASE, therefore
+ // if some unused provider is also available we need to mark it ERASE as well.
+ Solvable *s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(available_unused_providers.begin(), available_unused_providers.end(), s, NameSolvableComparator);
+ while (low != available_unused_providers.end() && (*low)->name == s->name) {
+ queue_push2(job, SOLVER_ERASE | SOLVER_SOLVABLE, pool_solvable2id(pool, *low));
+ ++low;
+ }
+ }
+ queue_push2(job, action | SOLVER_SOLVABLE, id);
+ }
+ }
+ }
+ return reresolve;
+}
+
+bool
+Goal::Impl::solve(Queue *job, DnfGoalActions flags)
+{
+ /* apply the excludes */
+ dnf_sack_recompute_considered(sack);
+
+ dnf_sack_make_provides_ready(sack);
+ if (trans) {
+ transaction_free(trans);
+ trans = NULL;
+ }
+
+ Solver *solv = initSolver();
+
+ /* Removal of SOLVER_WEAK to allow report errors*/
+ if (DNF_IGNORE_WEAK & flags) {
+ for (int i = 0; i < job->count; i += 2) {
+ job->elements[i] &= ~SOLVER_WEAK;
+ }
+ }
+
+ if (DNF_IGNORE_WEAK_DEPS & flags)
+ solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
+
+ if (DNF_ALLOW_DOWNGRADE & actions)
+ solver_set_flag(solv, SOLVER_FLAG_ALLOW_DOWNGRADE, 1);
+
+ if (solver_solve(solv, job))
+ return true;
+ // either allow solutions callback or installonlies, both at the same time
+ // are not supported
+ if (limitInstallonlyPackages(solv, job)) {
+ // allow erasing non-installonly packages that depend on a kernel about
+ // to be erased
+ allowUninstallAllButProtected(job, DNF_ALLOW_UNINSTALL);
+ if (solver_solve(solv, job))
+ return true;
+ }
+ trans = solver_create_transaction(solv);
+
+ if (protectedInRemovals())
+ return true;
+
+ return false;
+}
+
+/**
+ * Reports packages that has a conflict
+ *
+ * Returns Queue with Ids of packages with conflict
+ */
+std::unique_ptr<IdQueue>
+Goal::Impl::conflictPkgs(unsigned i)
+{
+ SolverRuleinfo type;
+ Id rid, source, target, dep;
+ std::unique_ptr<IdQueue> conflict(new IdQueue);
+ if (i >= solver_problem_count(solv))
+ return conflict;
+
+ IdQueue pq;
+ // this libsolv interface indexes from 1 (we do from 0), so:
+ solver_findallproblemrules(solv, i+1, pq.getQueue());
+ for ( int j = 0; j < pq.size(); j++) {
+ rid = pq[j];
+ type = solver_ruleinfo(solv, rid, &source, &target, &dep);
+ if (type == SOLVER_RULE_PKG_CONFLICTS)
+ conflict->pushBack(source, target);
+ else if (type == SOLVER_RULE_PKG_SELF_CONFLICT)
+ conflict->pushBack(source);
+ else if (type == SOLVER_RULE_PKG_SAME_NAME)
+ conflict->pushBack(source, target);
+ }
+ return conflict;
+}
+
+int
+Goal::Impl::countProblems()
+{
+ assert(solv);
+ size_t protectedSize = removalOfProtected ? removalOfProtected->size() : 0;
+ return solver_problem_count(solv) + MIN(1, protectedSize);
+}
+
+std::unique_ptr<PackageSet>
+Goal::Impl::brokenDependencyAllPkgs(DnfPackageState pkg_type)
+{
+ Pool * pool = dnf_sack_get_pool(sack);
+
+ std::unique_ptr<PackageSet> pset(new PackageSet(sack));
+ PackageSet temporary_pset(sack);
+
+ int countProblemsValue = countProblems();
+ for (int i = 0; i < countProblemsValue; i++) {
+ auto broken_dependency = brokenDependencyPkgs(i);
+ for (int j = 0; j < broken_dependency->size(); j++) {
+ Id id = (*broken_dependency)[j];
+ Solvable *s = pool_id2solvable(pool, id);
+ bool installed = pool->installed == s->repo;
+ if (pkg_type == DNF_PACKAGE_STATE_AVAILABLE && installed) {
+ temporary_pset.set(id);
+ continue;
+ }
+ if (pkg_type == DNF_PACKAGE_STATE_INSTALLED && !installed)
+ continue;
+ pset->set(id);
+ }
+ }
+ if (!temporary_pset.size()) {
+ return pset;
+ }
+ return remove_pkgs_with_same_nevra_from_pset(pset.get(), &temporary_pset, sack);
+}
+
+/**
+ * Reports packages that have broken dependency
+ *
+ * Returns Queue with Ids of packages with broken dependency
+ */
+std::unique_ptr<IdQueue>
+Goal::Impl::brokenDependencyPkgs(unsigned i)
+{
+ SolverRuleinfo type;
+ Id rid, source, target, dep;
+
+ auto broken_dependency = std::unique_ptr<IdQueue>(new IdQueue);
+ if (i >= solver_problem_count(solv))
+ return broken_dependency;
+ IdQueue pq;
+ // this libsolv interface indexes from 1 (we do from 0), so:
+ solver_findallproblemrules(solv, i+1, pq.getQueue());
+ for (int j = 0; j < pq.size(); j++) {
+ rid = pq[j];
+ type = solver_ruleinfo(solv, rid, &source, &target, &dep);
+ if (type == SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP)
+ broken_dependency->pushBack(source);
+ else if (type == SOLVER_RULE_PKG_REQUIRES)
+ broken_dependency->pushBack(source);
+ }
+ return broken_dependency;
+}
+
+Id
+Goal::Impl::protectedRunningKernel()
+{
+ return protect_running_kernel ? dnf_sack_running_kernel(sack) : 0;
+}
+
+bool
+Goal::Impl::protectedInRemovals()
+{
+ guint i = 0;
+ bool ret = false;
+ if ((!protectedPkgs || !protectedPkgs->size()) && !protect_running_kernel)
+ return false;
+ auto pkgRemoveList = listResults(SOLVER_TRANSACTION_ERASE, 0);
+ Id protected_kernel = protectedRunningKernel();
+ auto pkgObsoleteList = listResults(SOLVER_TRANSACTION_OBSOLETED, 0);
+ // Special case: consider the obsoletion of the running kernel as a
+ // removal. Obsoletion of other protected packages should be allowed.
+ for (size_t obsolete_index = 0; obsolete_index < pkgObsoleteList.size(); obsolete_index += 1) {
+ if (protected_kernel == pkgObsoleteList[obsolete_index]) {
+ pkgRemoveList.set(protected_kernel);
+ }
+ }
+
+ // We want to allow obsoletion of protected packages, so we do not consider
+ // obsoletes here, only removes. Previously, obsoletion of protected
+ // packages was disallowed, but there needed to be some mechanism for
+ // obsoleting/swapping a protected package, such as to obsolete `dnf` in
+ // favor of `dnf5`. Obsoleting a package is much harder to do accidentally
+ // than removing it.
+ removalOfProtected.reset(new PackageSet(pkgRemoveList));
+ Id id = -1;
+ while(true) {
+ id = removalOfProtected->next(id);
+ if (id == -1)
+ break;
+
+ if (protectedPkgs->has(id) || id == protected_kernel) {
+ ret = true;
+ i++;
+ } else {
+ removalOfProtected->remove(id);
+ }
+ }
+ return ret;
+}
+
+/**
+ * String describing the removal of protected packages.
+ */
+std::string
+Goal::Impl::describeProtectedRemoval()
+{
+ std::string message(_("The operation would result in removing"
+ " the following protected packages: "));
+ Pool * pool = solv->pool;
+
+ if (removalOfProtected && removalOfProtected->size()) {
+ Id id = -1;
+ std::vector<const char *> names;
+ while((id = removalOfProtected->next(id)) != -1) {
+ Solvable * s = pool_id2solvable(pool, id);
+ names.push_back(pool_id2str(pool, s->name));
+ }
+ if (names.empty()) {
+ return {};
+ }
+ return message + std::accumulate(std::next(names.begin()), names.end(),
+ std::string(names[0]), [](std::string a, std::string b) { return a + ", " + b; });
+ }
+ auto pset = brokenDependencyAllPkgs(DNF_PACKAGE_STATE_INSTALLED);
+ Id id = -1;
+ Id protected_kernel = protectedRunningKernel();
+ std::vector<const char *> names;
+ while((id = pset->next(id)) != -1) {
+ if (protectedPkgs->has(id) || id == protected_kernel) {
+ Solvable * s = pool_id2solvable(pool, id);
+ names.push_back(pool_id2str(pool, s->name));
+ }
+ }
+ if (names.empty())
+ return {};
+ return message + std::accumulate(std::next(names.begin()), names.end(), std::string(names[0]),
+ [](std::string a, std::string b) { return a + ", " + b; });
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GOAL_HPP
+#define __GOAL_HPP
+
+#include <memory>
+#include <stdexcept>
+#include <vector>
+
+#include "../dnf-types.h"
+#include "../error.hpp"
+#include "../hy-goal.h"
+#include "../hy-package.h"
+
+namespace libdnf {
+
+struct Goal {
+public:
+ struct Error : public libdnf::Error {
+ Error(const std::string & msg, int errCode) : libdnf::Error(msg), errCode(errCode) {}
+ Error(const char * msg, int errCode) : libdnf::Error(msg), errCode(errCode) {}
+ int getErrCode() const noexcept { return errCode; }
+ private:
+ int errCode;
+ };
+
+ Goal(DnfSack *sack);
+ Goal(const Goal & goal_src);
+ Goal(Goal && goal_src) = delete;
+ ~Goal();
+
+ DnfGoalActions getActions();
+ int getReason(DnfPackage *pkg);
+ DnfSack * getSack();
+
+ void addProtected(PackageSet & pset);
+ void setProtected(const PackageSet & pset);
+
+ bool get_protect_running_kernel() const noexcept;
+ void set_protect_running_kernel(bool value);
+
+ void distupgrade();
+ void distupgrade(DnfPackage *new_pkg);
+
+ /**
+ * @brief If selector ill formed, it rises std::runtime_error()
+ */
+ void distupgrade(HySelector);
+ void erase(DnfPackage *pkg, int flags = 0);
+
+ /**
+ * @brief If selector ill formed, it rises std::runtime_error()
+ *
+ * @param sltr
+ * @param flags p_flags:...
+ */
+ void erase(HySelector sltr, int flags);
+ void install(DnfPackage *new_pkg, bool optional);
+ void lock(DnfPackage *new_pkg);
+ void favor(DnfPackage *new_pkg);
+ void add_exclude_from_weak(const DnfPackageSet & pset);
+ void add_exclude_from_weak(DnfPackage *pkg);
+ void reset_exclude_from_weak();
+ void exclude_from_weak_autodetect();
+ void disfavor(DnfPackage *new_pkg);
+
+ /**
+ * @brief If selector ill formed, it rises std::runtime_error()
+ *
+ * @param sltr p_sltr:...
+ * @param optional Set true for optional tasks, false for strict tasks
+ */
+ void install(HySelector sltr, bool optional);
+
+ /**
+ * @brief Add upgrade all packages request to job. It adds obsoletes automatically to transaction
+ */
+ void upgrade();
+ void upgrade(DnfPackage *new_pkg);
+
+ /**
+ * @brief If selector ill formed, it rises std::runtime_error()
+ *
+ * @param sltr p_sltr: It contains upgrade-to packages and obsoletes. The presence of installed
+ * packages prevents reinstalling packages with the same NEVRA but changed contant. To honor repo
+ * priority all relevant packages must be present. To upgrade package foo from priority repo, all
+ * installed and available packages of the foo must be in selector plus obsoletes of foo.
+ */
+ void upgrade(HySelector sltr);
+ void userInstalled(DnfPackage *pkg);
+ void userInstalled(PackageSet & pset);
+
+ /* introspecting the requests */
+ bool hasActions(DnfGoalActions action);
+
+ int jobLength();
+
+ /* resolving the goal */
+ bool run(DnfGoalActions flags);
+
+ /* problems */
+ int countProblems();
+
+ std::unique_ptr<PackageSet> listConflictPkgs(DnfPackageState pkg_type);
+ std::unique_ptr<PackageSet> listBrokenDependencyPkgs(DnfPackageState pkg_type);
+ std::vector<std::vector<std::string>> describeAllProblemRules(bool pkgs);
+
+ /**
+ * @brief Check if any solver resolution problem is a file dependency issue
+ */
+ bool isBrokenFileDependencyPresent();
+
+ /**
+ * @brief List describing failed rules in solving problem 'i'. Caller is responsible for freeing the
+ * returned string list by g_free().
+ *
+ * @param goal HyGoal
+ * @param i ingex of problem
+ * @param pkgs if true packages problem messages, othewise module messages are used
+ * @return char**
+ */
+ std::vector<std::string> describeProblemRules(unsigned i, bool pkgs);
+ int logDecisions();
+ void writeDebugdata(const char *dir);
+
+ /* result processing */
+ PackageSet listErasures();
+ PackageSet listInstalls();
+ PackageSet listObsoleted();
+ PackageSet listReinstalls();
+ PackageSet listUnneeded();
+ PackageSet listSuggested();
+ PackageSet listUpgrades();
+ PackageSet listDowngrades();
+ PackageSet listObsoletedByPackage(DnfPackage * pkg);
+
+ /// Concentrate all problems into a string
+ static std::string formatAllProblemRules(const std::vector<std::vector<std::string>> & problems);
+private:
+ friend Query;
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif /* __GOAL_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __ID_QUEUE_HPP
+#define __ID_QUEUE_HPP
+
+#include <utility>
+
+extern "C" {
+#include <solv/queue.h>
+}
+
+namespace libdnf {
+
+struct IdQueue {
+public:
+ IdQueue();
+ IdQueue(const IdQueue & src);
+ IdQueue(IdQueue && src);
+ explicit IdQueue(const Queue & src);
+ ~IdQueue();
+
+ void pushBack(Id id);
+ void pushBack(Id id1, Id id2);
+ Id operator[](int index) const;
+ int * data() const noexcept;
+ Queue * getQueue() noexcept;
+ int size() const noexcept;
+ void clear() noexcept;
+
+private:
+ Queue queue;
+
+};
+
+inline IdQueue::IdQueue() { queue_init(&queue); }
+inline IdQueue::IdQueue(const IdQueue & src) { queue_init_clone(&queue, &src.queue); }
+inline IdQueue::IdQueue(IdQueue && src)
+{
+ queue_init(&queue);
+ std::swap(queue, src.queue);
+}
+inline IdQueue::IdQueue(const Queue & src) { queue_init_clone(&queue, &src); }
+
+inline IdQueue::~IdQueue() { queue_free(&queue); }
+
+inline void IdQueue::pushBack(Id id) { queue_push(&queue, id); }
+inline void IdQueue::pushBack(Id id1, Id id2) { queue_push2(&queue, id1, id2); }
+inline Id IdQueue::operator[](int index) const { return queue.elements[index]; }
+inline int * IdQueue::data() const noexcept { return queue.elements; }
+inline Queue * IdQueue::getQueue() noexcept { return &queue; }
+inline int IdQueue::size() const noexcept { return queue.count; }
+inline void IdQueue::clear() noexcept { queue_empty(&queue); }
+
+}
+
+#endif /* __ID_QUEUE_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_GOAL_INTERNAL_H
+#define HY_GOAL_INTERNAL_H
+
+// libsolv
+#include <solv/queue.h>
+#include <solv/transaction.h>
+#include <solv/solver.h>
+
+// hawkey
+#include "hy-goal.h"
+
+inline DnfGoalActions operator|(DnfGoalActions a, DnfGoalActions b)
+{
+ return static_cast<DnfGoalActions>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline DnfGoalActions & operator|=(DnfGoalActions & a, DnfGoalActions b)
+{
+ return a = a | b;
+}
+
+namespace libdnf {
+
+void sltrToJob(const HySelector sltr, Queue *job, int solver_action);
+
+}
+
+#endif // HY_GOAL_INTERNAL_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// libsolv
+extern "C" {
+#include <solv/evr.h>
+#include <solv/policy.h>
+#include <solv/selection.h>
+#include <solv/solver.h>
+#include <solv/solverdebug.h>
+#include <solv/testcase.h>
+#include <solv/transaction.h>
+#include <solv/util.h>
+#include <solv/poolid.h>
+}
+
+// hawkey
+#include "catch-error.hpp"
+#include "dnf-context.hpp"
+#include "dnf-types.h"
+#include "hy-goal-private.hpp"
+#include "hy-iutil-private.hpp"
+#include "hy-package-private.hpp"
+#include "hy-packageset-private.hpp"
+#include "hy-query-private.hpp"
+#include "hy-repo-private.hpp"
+#include "dnf-sack-private.hpp"
+#include "dnf-goal.h"
+#include "dnf-package.h"
+#include "hy-selector-private.hpp"
+#include "hy-util-private.hpp"
+#include "dnf-package.h"
+#include "hy-package.h"
+#include "goal/Goal.hpp"
+#include "sack/packageset.hpp"
+
+#include "utils/bgettext/bgettext-lib.h"
+
+#define BLOCK_SIZE 15
+
+
+// public functions
+
+HyGoal
+hy_goal_clone(HyGoal goal)
+{
+ auto goal_clone = new libdnf::Goal(*goal);
+ goal_clone->set_protect_running_kernel(
+ libdnf::getGlobalMainConfig().protect_running_kernel().getValue());
+ return goal_clone;
+}
+
+HyGoal
+hy_goal_create(DnfSack *sack)
+{
+ auto goal = new libdnf::Goal(sack);
+ goal->set_protect_running_kernel(
+ libdnf::getGlobalMainConfig().protect_running_kernel().getValue());
+ return goal;
+}
+
+void
+hy_goal_free(HyGoal goal)
+{
+ delete goal;
+}
+
+DnfSack *
+hy_goal_get_sack(HyGoal goal)
+{
+ return goal->getSack();
+}
+
+int
+hy_goal_distupgrade_all(HyGoal goal)
+{
+ goal->distupgrade();
+ return 0;
+}
+
+int
+hy_goal_distupgrade(HyGoal goal, DnfPackage *new_pkg)
+{
+ goal->distupgrade(new_pkg);
+ return 0;
+}
+
+int
+hy_goal_distupgrade_selector(HyGoal goal, HySelector sltr)
+{
+ try {
+ goal->distupgrade(sltr);
+ } catch (libdnf::Goal::Error & e) {
+ return e.getErrCode();
+ }
+ return 0;
+}
+
+int
+hy_goal_downgrade_to(HyGoal goal, DnfPackage *new_pkg)
+{
+ goal->install(new_pkg, false);
+ return 0;
+}
+
+int
+hy_goal_erase(HyGoal goal, DnfPackage *pkg)
+{
+ goal->erase(pkg);
+ return 0;
+}
+
+int
+hy_goal_erase_flags(HyGoal goal, DnfPackage *pkg, int flags)
+{
+ goal->erase(pkg, flags);
+ return 0;
+}
+
+int
+hy_goal_erase_selector_flags(HyGoal goal, HySelector sltr, int flags)
+{
+ try {
+ goal->erase(sltr, flags);
+ } catch (libdnf::Goal::Error & e) {
+ return e.getErrCode();
+ }
+ return 0;
+}
+
+int
+hy_goal_has_actions(HyGoal goal, DnfGoalActions action)
+{
+ return goal->hasActions(action);
+}
+
+int
+hy_goal_install(HyGoal goal, DnfPackage *new_pkg)
+{
+ goal->install(new_pkg, false);
+ return 0;
+}
+
+int
+hy_goal_install_optional(HyGoal goal, DnfPackage *new_pkg)
+{
+ goal->install(new_pkg, true);
+ return 0;
+}
+
+int
+hy_goal_lock(HyGoal goal, DnfPackage *pkg, GError **error)
+{
+ goal->lock(pkg);
+ return 0;
+}
+
+int
+hy_goal_favor(HyGoal goal, DnfPackage *pkg)
+{
+ goal->favor(pkg);
+ return 0;
+}
+
+int
+hy_goal_disfavor(HyGoal goal, DnfPackage *pkg)
+{
+ goal->disfavor(pkg);
+ return 0;
+}
+
+gboolean
+hy_goal_install_selector(HyGoal goal, HySelector sltr, GError **error) try
+{
+ goal->install(sltr, false);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+hy_goal_install_selector_optional(HyGoal goal, HySelector sltr, GError **error) try
+{
+ goal->install(sltr, true);
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+int
+hy_goal_upgrade_all(HyGoal goal)
+{
+ goal->upgrade();
+ return 0;
+}
+
+int
+hy_goal_upgrade_to(HyGoal goal, DnfPackage *new_pkg)
+{
+ goal->upgrade(new_pkg);
+ return 0;
+}
+
+int
+hy_goal_upgrade_selector(HyGoal goal, HySelector sltr)
+{
+ try {
+ goal->upgrade(sltr);
+ } catch (libdnf::Goal::Error & e) {
+ return e.getErrCode();
+ }
+ return 0;
+}
+
+int
+hy_goal_userinstalled(HyGoal goal, DnfPackage *pkg)
+{
+ goal->userInstalled(pkg);
+ return 0;
+}
+
+int hy_goal_req_length(HyGoal goal)
+{
+ return goal->jobLength();
+}
+
+int
+hy_goal_run_flags(HyGoal goal, DnfGoalActions flags)
+{
+ return goal->run(flags);
+}
+
+int
+hy_goal_count_problems(HyGoal goal)
+{
+ return goal->countProblems();
+}
+
+/**
+ * Reports packages that has a conflict
+ *
+ * available - if available it returns set with available packages with conflicts
+ * available - if package installed it also excludes available packages with same NEVRA
+ *
+ * Returns DnfPackageSet with all packages that have a conflict.
+ */
+DnfPackageSet *
+hy_goal_conflict_all_pkgs(HyGoal goal, DnfPackageState pkg_type)
+{
+ return goal->listConflictPkgs(pkg_type).release();
+}
+
+/**
+ * Reports all packages that have broken dependency
+ * available - if available returns only available packages with broken dependencies
+ * available - if package installed it also excludes available packages with same NEVRA
+ * Returns DnfPackageSet with all packages with broken dependency
+ */
+DnfPackageSet *
+hy_goal_broken_dependency_all_pkgs(HyGoal goal, DnfPackageState pkg_type)
+{
+ return goal->listBrokenDependencyPkgs(pkg_type).release();
+}
+
+/**
+ * Write all the solving decisions to the hawkey logfile.
+ */
+int
+hy_goal_log_decisions(HyGoal goal)
+{
+ return goal->logDecisions();
+}
+
+/**
+ * hy_goal_write_debugdata:
+ * @goal: A #HyGoal
+ * @dir: The directory to write to
+ * @error: A #GError, or %NULL
+ *
+ * Writes details about the testcase to a directory.
+ *
+ * Returns: %FALSE if an error was set
+ *
+ * Since: 0.7.0
+ */
+bool
+hy_goal_write_debugdata(HyGoal goal, const char *dir, GError **error) try
+{
+ goal->writeDebugdata(dir);
+ return true;
+} CATCH_TO_GERROR(false)
+
+GPtrArray *
+hy_goal_list_erasures(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listErasures();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_installs(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listInstalls();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_obsoleted(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listObsoleted();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_reinstalls(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listReinstalls();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_unneeded(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listUnneeded();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_suggested(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listSuggested();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_upgrades(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listUpgrades();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_downgrades(HyGoal goal, GError **error) try
+{
+ auto pset = goal->listDowngrades();
+ return packageSet2GPtrArray(&pset);
+} CATCH_TO_GERROR(NULL)
+
+GPtrArray *
+hy_goal_list_obsoleted_by_package(HyGoal goal, DnfPackage *pkg)
+{
+ auto pset = goal->listObsoletedByPackage(pkg);
+ return packageSet2GPtrArray(&pset);
+}
+
+int
+hy_goal_get_reason(HyGoal goal, DnfPackage *pkg)
+{
+ return goal->getReason(pkg);
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_GOAL_H
+#define HY_GOAL_H
+
+#include <glib.h>
+#include <stdbool.h>
+
+G_BEGIN_DECLS
+
+#include "hy-types.h"
+#include "dnf-sack.h"
+#include "dnf-utils.h"
+
+enum _hy_goal_op_flags {
+ HY_CHECK_INSTALLED = 1 << 0,
+ HY_CLEAN_DEPS = 1 << 1,
+ HY_WEAK_SOLV = 1 << 2
+};
+
+typedef enum {
+ DNF_NONE = 0,
+ DNF_ERASE = 1 << 0,
+ DNF_DISTUPGRADE = 1 << 1,
+ DNF_DISTUPGRADE_ALL = 1 << 2,
+ DNF_DOWNGRADE = 1 << 3,
+ DNF_INSTALL = 1 << 4,
+ DNF_UPGRADE = 1 << 5,
+ DNF_UPGRADE_ALL = 1 << 6,
+
+ // hy_goal_run flags
+ DNF_ALLOW_UNINSTALL = 1 << 10,
+ DNF_FORCE_BEST = 1 << 11,
+ DNF_VERIFY = 1 << 12,
+ DNF_IGNORE_WEAK_DEPS = 1 << 13,
+ DNF_ALLOW_DOWNGRADE = 1 << 14,
+ DNF_IGNORE_WEAK = 1 << 15
+} DnfGoalActions;
+
+typedef enum {
+ DNF_PACKAGE_STATE_ALL = 0,
+ DNF_PACKAGE_STATE_AVAILABLE = 1,
+ DNF_PACKAGE_STATE_INSTALLED = 2
+} DnfPackageState;
+
+#define HY_REASON_DEP 1
+#define HY_REASON_USER 2
+#define HY_REASON_CLEAN 3
+#define HY_REASON_WEAKDEP 4
+
+HyGoal hy_goal_create(DnfSack *sack);
+HyGoal hy_goal_clone(HyGoal goal);
+void hy_goal_free(HyGoal goal);
+DnfSack *hy_goal_get_sack(HyGoal goal);
+
+int hy_goal_distupgrade_all(HyGoal goal);
+int hy_goal_distupgrade(HyGoal goal, DnfPackage *new_pkg);
+int hy_goal_distupgrade_selector(HyGoal goal, HySelector);
+
+/**
+* @brief Mark a package to install. It doesn't check if the package has a lower version than
+* installed package or even installed. It allows to downgrade dependencies if needed. It return
+* always 0.
+*
+* @param goal HyGoal
+* @param new_pkg DnfPackage
+* @return int
+*/
+DEPRECATED("Will be removed after 2018-03-01. Use hy_goal_install() instead.")
+int hy_goal_downgrade_to(HyGoal goal, DnfPackage *new_pkg);
+int hy_goal_erase(HyGoal goal, DnfPackage *pkg);
+int hy_goal_erase_flags(HyGoal goal, DnfPackage *pkg, int flags);
+
+/**
+ * Erase packages specified by the Selector.
+ *
+ * @returns 0 on success, DNF_ERROR_BAD_SELECTOR for an invalid Selector.
+ */
+int hy_goal_erase_selector_flags(HyGoal goal, HySelector sltr, int flags);
+
+/**
+* @brief Mark package to install or if installed to downgrade or upgrade. It allows to downgrade
+* dependencies if needed. Return value is always 0.
+*
+* @param goal HyGoal
+* @param new_pkg Package to install
+* @return int
+*/
+int hy_goal_install(HyGoal goal, DnfPackage *new_pkg);
+
+/**
+* @brief Mark package to install or if installed to downgrade or upgrade. In case that package
+* cannot be install, it can be skipped without an error. It allows to downgrade dependencies if
+* needed. Return value is always 0.
+*
+* @param goal HyGoal
+* @param new_pkg Package to install
+* @return int
+*/
+int hy_goal_install_optional(HyGoal goal, DnfPackage *new_pkg);
+
+/**
+* @brief Lock package state. If installed, remains installed. If uninstalled,
+* remains uninstalled. Returns 0 on success.
+*
+* @param goal HyGoal
+* @param pkg Package to lock
+* @return int
+*/
+int hy_goal_lock(HyGoal goal, DnfPackage *pkg, GError **error);
+
+/**
+* @brief Favor package when considering alternatives. Return value is always 0.
+*
+* @param goal HyGoal
+* @param pkg Package to favor
+* @return int
+*/
+int hy_goal_favor(HyGoal goal, DnfPackage *pkg);
+
+/**
+* @brief Disfavor package when considering alternatives. Return value is always 0.
+*
+* @param goal HyGoal
+* @param pkg Package to disfavor
+* @return int
+*/
+int hy_goal_disfavor(HyGoal goal, DnfPackage *pkg);
+
+/**
+* @brief Mark content of HySelector to install or if installed to downgrade or upgrade. Only one
+* option will be chosen. It allows to downgrade dependencies if needed. If not supported
+* combination in selectort, it triggers assertion raise.
+*
+* @param goal HyGoal
+* @param sltr HySelector
+* @param error p_error:...
+* @return gboolean
+*/
+gboolean hy_goal_install_selector(HyGoal goal, HySelector sltr, GError **error);
+
+/**
+* @brief Mark content of HySelector to install or if installed to downgrade or upgrade. In case that
+* any package in selector cannot be install, it can be skipped without an error. Only one option
+* will be chosen. It allows to downgrade dependencies if needed. If not supported combination in
+* selectort, it triggers assertion raise.
+*
+* @param goal HyGoal
+* @param sltr HySelector
+* @param error p_error:...
+* @return gboolean
+*/
+gboolean hy_goal_install_selector_optional(HyGoal goal, HySelector sltr, GError **error);
+int hy_goal_upgrade_all(HyGoal goal);
+int hy_goal_upgrade_to(HyGoal goal, DnfPackage *new_pkg);
+int hy_goal_upgrade_selector(HyGoal goal, HySelector sltr);
+int hy_goal_userinstalled(HyGoal goal, DnfPackage *pkg);
+
+/* introspecting the requests */
+int hy_goal_has_actions(HyGoal goal, DnfGoalActions action);
+
+int hy_goal_req_length(HyGoal goal);
+
+/* resolving the goal */
+int hy_goal_run_flags(HyGoal goal, DnfGoalActions flags);
+
+/* problems */
+int hy_goal_count_problems(HyGoal goal);
+DnfPackageSet *hy_goal_conflict_all_pkgs(HyGoal goal, DnfPackageState pkg_type);
+DnfPackageSet *hy_goal_broken_dependency_all_pkgs(HyGoal goal, DnfPackageState pkg_type);
+
+int hy_goal_log_decisions(HyGoal goal);
+bool hy_goal_write_debugdata(HyGoal goal, const char *dir, GError **error);
+
+/* result processing */
+GPtrArray *hy_goal_list_erasures(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_installs(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_obsoleted(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_reinstalls(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_unneeded(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_suggested(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_upgrades(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_downgrades(HyGoal goal, GError **error);
+GPtrArray *hy_goal_list_obsoleted_by_package(HyGoal goal, DnfPackage *pkg);
+int hy_goal_get_reason(HyGoal goal, DnfPackage *pkg);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_IUTIL_PRIVATE_HPP
+#define HY_IUTIL_PRIVATE_HPP
+
+#include "hy-iutil.h"
+#include "hy-types.h"
+#include "sack/packageset.hpp"
+#include <array>
+#include <utility>
+
+// Use 8 bytes for libsolv version (API: solv_toolversion)
+// to be future proof even though it currently is "1.2"
+static constexpr const size_t solv_userdata_solv_toolversion_size{8};
+static constexpr const std::array<char, 4> solv_userdata_magic{'\0', 'd', 'n', 'f'};
+static constexpr const std::array<char, 4> solv_userdata_dnf_version{'\0', '1', '.', '0'};
+
+static constexpr const int solv_userdata_size = solv_userdata_solv_toolversion_size + \
+ solv_userdata_magic.size() + \
+ solv_userdata_dnf_version.size() + \
+ CHKSUM_BYTES;
+
+struct SolvUserdata {
+ char dnf_magic[solv_userdata_magic.size()];
+ char dnf_version[solv_userdata_dnf_version.size()];
+ char libsolv_version[solv_userdata_solv_toolversion_size];
+ unsigned char checksum[CHKSUM_BYTES];
+}__attribute__((packed)); ;
+
+int solv_userdata_fill(SolvUserdata *solv_userdata, const unsigned char *checksum, GError** error);
+std::unique_ptr<SolvUserdata, decltype(solv_free)*> solv_userdata_read(FILE *fp);
+int solv_userdata_verify(const SolvUserdata *solv_userdata, const unsigned char *checksum);
+
+/* crypto utils */
+int checksum_cmp(const unsigned char *cs1, const unsigned char *cs2);
+int checksum_fp(unsigned char *out, FILE *fp);
+int checksum_stat(unsigned char *out, FILE *fp);
+int checksumt_l2h(int type);
+const char *pool_checksum_str(Pool *pool, const unsigned char *chksum);
+
+const char *id2nevra(Pool *pool, Id id);
+
+/* filesystem utils */
+char *abspath(const char *path);
+int is_readable_rpm(const char *fn);
+int mkcachedir(char *path);
+gboolean mv(const char *old_path, const char *new_path, GError **error);
+gboolean dnf_remove_recursive_v2(const gchar *path, GError **error);
+gboolean dnf_copy_file(const std::string & srcPath, const std::string & dstPath, GError ** error);
+gboolean dnf_copy_recursive(const std::string & srcPath, const std::string & dstPath, GError ** error);
+gboolean dnf_move_recursive(const gchar *src_dir, const gchar *dst_dir, GError **error);
+char *this_username(void);
+
+/* misc utils */
+char *read_whole_file(const char *path);
+Id running_kernel(DnfSack *sack);
+
+/* libsolv utils */
+Repo *repo_by_name(DnfSack *sack, const char *name);
+HyRepo hrepo_by_name(DnfSack *sack, const char *name);
+Id str2archid(Pool *pool, const char *s);
+Id what_upgrades(Pool *pool, Id p);
+Id what_downgrades(Pool *pool, Id p);
+Map *free_map_fully(Map *m);
+int is_package(const Pool *pool, const Solvable *s);
+
+/* package version utils */
+unsigned long pool_get_epoch(Pool *pool, const char *evr);
+void pool_split_evr(Pool *pool, const char *evr, char **epoch, char **version, char **release);
+
+/* reldep utils */
+int parse_reldep_str(const char *nevra, char **name, char **evr, int *cmp_type);
+GPtrArray * packageSet2GPtrArray(libdnf::PackageSet * pset);
+
+/* loop over all package providers of d */
+#define FOR_PKG_PROVIDES(v, vp, d) \
+ FOR_PROVIDES(v, vp, d) \
+ if (!is_package(pool, pool_id2solvable(pool, v))) \
+ continue; \
+ else
+
+/* loop over all package solvables */
+#define FOR_PKG_SOLVABLES(p) \
+ FOR_POOL_SOLVABLES(p) \
+ if (!is_package(pool, pool_id2solvable(pool, p))) \
+ continue; \
+ else
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#ifdef __APPLE__
+#include <limits.h>
+#else
+#include <linux/limits.h>
+#endif
+#include <pwd.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <wordexp.h>
+
+// libsolv
+extern "C" {
+#include <solv/chksum.h>
+#include <solv/evr.h>
+#include <solv/solver.h>
+#include <solv/solverdebug.h>
+#include <solv/repo_solv.h>
+#include <solv/util.h>
+#include <solv/pool_parserpmrichdep.h>
+}
+
+// hawkey
+#include "catch-error.hpp"
+#include "dnf-advisory-private.hpp"
+#include "dnf-types.h"
+#include "hy-iutil-private.hpp"
+#include "hy-package-private.hpp"
+#include "hy-packageset-private.hpp"
+#include "hy-query.h"
+#include "hy-util-private.hpp"
+#include "dnf-sack-private.hpp"
+#include "sack/packageset.hpp"
+
+#include "utils/bgettext/bgettext-lib.h"
+#include "sack/packageset.hpp"
+
+// glib
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
+#define BUF_BLOCK 4096
+#define CHKSUM_TYPE REPOKEY_TYPE_SHA256
+#define CHKSUM_IDENT "H000"
+#define CACHEDIR_PERMISSIONS 0700
+
+static mode_t
+get_umask(void)
+{
+ mode_t mask = umask(0);
+ umask(mask);
+ return mask;
+}
+
+static int
+glob_for_cachedir(char *path)
+{
+ int ret = 1;
+ if (!g_str_has_suffix(path, "XXXXXX"))
+ return ret;
+
+ wordexp_t word_vector;
+ char *p = g_strdup(path);
+ const int len = strlen(p);
+ struct stat s;
+
+ ret = 2;
+ p[len-6] = '*';
+ p[len-5] = '\0';
+ if (wordexp(p, &word_vector, 0)) {
+ g_free(p);
+ return ret;
+ }
+ for (guint i = 0; i < word_vector.we_wordc; ++i) {
+ char *entry = word_vector.we_wordv[i];
+ if (stat(entry, &s))
+ continue;
+ if (S_ISDIR(s.st_mode) &&
+ s.st_uid == getuid()) {
+ assert(strlen(path) == strlen(entry));
+ strcpy(path, entry);
+ ret = 0;
+ break;
+ }
+ }
+ wordfree(&word_vector);
+ g_free(p);
+ return ret;
+}
+
+int
+checksum_cmp(const unsigned char *cs1, const unsigned char *cs2)
+{
+ return memcmp(cs1, cs2, CHKSUM_BYTES);
+}
+
+/* calls rewind(fp) before returning */
+int
+checksum_fp(unsigned char *out, FILE *fp)
+{
+ /* based on calc_checksum_fp in libsolv's solv.c */
+ char buf[4096];
+ auto h = solv_chksum_create(CHKSUM_TYPE);
+ int l;
+
+ rewind(fp);
+ solv_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT));
+ while ((l = fread(buf, 1, sizeof(buf), fp)) > 0)
+ solv_chksum_add(h, buf, l);
+ rewind(fp);
+ solv_chksum_free(h, out);
+ return 0;
+}
+
+/* does not move the fp position */
+int
+checksum_stat(unsigned char *out, FILE *fp)
+{
+ assert(fp);
+
+ struct stat stat;
+ if (fstat(fileno(fp), &stat))
+ return 1;
+
+ /* based on calc_checksum_stat in libsolv's solv.c */
+ auto h = solv_chksum_create(CHKSUM_TYPE);
+ solv_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT));
+ solv_chksum_add(h, &stat.st_dev, sizeof(stat.st_dev));
+ solv_chksum_add(h, &stat.st_ino, sizeof(stat.st_ino));
+ solv_chksum_add(h, &stat.st_size, sizeof(stat.st_size));
+ solv_chksum_add(h, &stat.st_mtime, sizeof(stat.st_mtime));
+ solv_chksum_free(h, out);
+ return 0;
+}
+
+static std::array<char, solv_userdata_solv_toolversion_size>
+get_padded_solv_toolversion()
+{
+ std::array<char, solv_userdata_solv_toolversion_size> padded_solv_toolversion{};
+ std::string solv_ver_str{solv_toolversion};
+ std::copy(solv_ver_str.rbegin(), solv_ver_str.rend(), padded_solv_toolversion.rbegin());
+
+ return padded_solv_toolversion;
+}
+
+int
+solv_userdata_fill(SolvUserdata *solv_userdata, const unsigned char *checksum, GError** error)
+{
+ if (strlen(solv_toolversion) > solv_userdata_solv_toolversion_size) {
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
+ _("Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"),
+ strlen(solv_toolversion), solv_userdata_solv_toolversion_size);
+ return 1;
+ }
+
+ // copy dnf solv file magic
+ memcpy(solv_userdata->dnf_magic, solv_userdata_magic.data(), solv_userdata_magic.size());
+
+ // copy dnf solv file version
+ memcpy(solv_userdata->dnf_version, solv_userdata_dnf_version.data(), solv_userdata_dnf_version.size());
+
+ // copy libsolv solv file version
+ memcpy(solv_userdata->libsolv_version, get_padded_solv_toolversion().data(), solv_userdata_solv_toolversion_size);
+
+ // copy checksum
+ memcpy(solv_userdata->checksum, checksum, CHKSUM_BYTES);
+
+ return 0;
+}
+
+
+std::unique_ptr<SolvUserdata, decltype(solv_free)*>
+solv_userdata_read(FILE *fp)
+{
+ unsigned char *dnf_solvfile_userdata_read = NULL;
+ int dnf_solvfile_userdata_len_read;
+ if (!fp) {
+ return {NULL, solv_free};
+ }
+
+ int ret_code = solv_read_userdata(fp, &dnf_solvfile_userdata_read, &dnf_solvfile_userdata_len_read);
+ // The userdata layout has to match our struct exactly so we can just cast the memory
+ // allocated by libsolv
+ std::unique_ptr<SolvUserdata, decltype(solv_free)*> uniq_userdata(
+ reinterpret_cast<SolvUserdata *>(dnf_solvfile_userdata_read),
+ solv_free);
+ if(ret_code) {
+ g_warning("Failed to read solv userdata: solv_read_userdata returned: %i", ret_code);
+ return uniq_userdata;
+ }
+
+ if (dnf_solvfile_userdata_len_read != solv_userdata_size) {
+ g_warning("Solv userdata length mismatch, read: %i vs expected: %i",
+ dnf_solvfile_userdata_len_read, solv_userdata_size);
+ return uniq_userdata;
+ }
+
+ return uniq_userdata;
+}
+
+gboolean
+solv_userdata_verify(const SolvUserdata *solv_userdata, const unsigned char *checksum)
+{
+ // check dnf solvfile magic bytes
+ if (memcmp(solv_userdata->dnf_magic, solv_userdata_magic.data(), solv_userdata_magic.size()) != 0) {
+ // This is not dnf header do not read after it
+ g_warning("magic bytes don't match, read: %s vs. dnf solvfile magic: %s",
+ solv_userdata->dnf_magic, solv_userdata_magic.data());
+ return FALSE;
+ }
+
+ // check dnf solvfile version
+ if (memcmp(solv_userdata->dnf_version, solv_userdata_dnf_version.data(), solv_userdata_dnf_version.size()) != 0) {
+ // Mismatching dnf solvfile version -> we need to regenerate
+ g_warning("dnf solvfile version doesn't match, read: %s vs. dnf solvfile version: %s",
+ solv_userdata->dnf_version, solv_userdata_dnf_version.data());
+ return FALSE;
+ }
+
+ // check libsolv solvfile version
+ if (memcmp(solv_userdata->libsolv_version, get_padded_solv_toolversion().data(), solv_userdata_solv_toolversion_size) != 0) {
+ // Mismatching libsolv solvfile version -> we need to regenerate
+ g_warning("libsolv solvfile version doesn't match, read: %s vs. libsolv version: %s",
+ solv_userdata->libsolv_version, solv_toolversion);
+ return FALSE;
+ }
+
+ // check solvfile checksum
+ if (checksum_cmp(solv_userdata->checksum, checksum)) {
+ // Mismatching solvfile checksum -> we need to regenerate
+ g_debug("solvfile checksum doesn't match, read: %s vs. repomd checksum: %s",
+ solv_userdata->checksum, checksum);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int
+checksum_type2length(int type)
+{
+ switch(type) {
+ case G_CHECKSUM_MD5:
+ return 16;
+ case G_CHECKSUM_SHA1:
+ return 20;
+ case G_CHECKSUM_SHA256:
+ return 32;
+ case G_CHECKSUM_SHA384:
+ return 48;
+ case G_CHECKSUM_SHA512:
+ return 64;
+ default:
+ return -1;
+ }
+}
+
+int
+checksumt_l2h(int type)
+{
+ switch (type) {
+ case REPOKEY_TYPE_MD5:
+ return G_CHECKSUM_MD5;
+ case REPOKEY_TYPE_SHA1:
+ return G_CHECKSUM_SHA1;
+ case REPOKEY_TYPE_SHA256:
+ return G_CHECKSUM_SHA256;
+ case REPOKEY_TYPE_SHA384:
+ return G_CHECKSUM_SHA384;
+ case REPOKEY_TYPE_SHA512:
+ return G_CHECKSUM_SHA512;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+const char *
+pool_checksum_str(Pool *pool, const unsigned char *chksum)
+{
+ int length = checksum_type2length(checksumt_l2h(CHKSUM_TYPE));
+ return pool_bin2hex(pool, chksum, length);
+}
+
+char *
+abspath(const char *path)
+{
+ const int len = strlen(path);
+ if (len <= 1)
+ return NULL;
+
+ if (path[0] == '/')
+ return g_strdup(path);
+
+ char cwd[PATH_MAX];
+ if (!getcwd(cwd, PATH_MAX)) {
+ return NULL;
+ }
+
+ return solv_dupjoin(cwd, "/", path);
+}
+
+Map *
+free_map_fully(Map *m)
+{
+ if (m == NULL)
+ return NULL;
+ map_free(m);
+ g_free(m);
+ return NULL;
+}
+
+int
+is_package(const Pool *pool, const Solvable *s)
+{
+ return !g_str_has_prefix(pool_id2str(pool, s->name), SOLVABLE_NAME_ADVISORY_PREFIX);
+}
+
+int
+is_readable_rpm(const char *fn)
+{
+ int len = strlen(fn);
+
+ if (access(fn, R_OK))
+ return 0;
+ if (len <= 4 || strcmp(fn + len - 4, ".rpm"))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Recursively create directory.
+ *
+ * If it is in the format accepted by mkdtemp() the function globs for a
+ * matching name and if not found it uses mkdtemp() to create the path. 'path'
+ * is modified in those two cases.
+ */
+int
+mkcachedir(char *path)
+{
+ int ret = 1;
+
+ if (!glob_for_cachedir(path))
+ return 0;
+
+ const int len = strlen(path);
+ if (len < 1 || path[0] != '/')
+ return 1; // only absolute pathnames are accepted
+
+ char *p = g_strdup(path);
+
+ if (p[len-1] == '/')
+ p[len-1] = '\0';
+
+ if (access(p, X_OK)) {
+ *(strrchr(p, '/')) = '\0';
+ ret = mkcachedir(p);
+ if (g_str_has_suffix(path, "XXXXXX")) {
+ char *retptr = mkdtemp(path);
+ if (retptr == NULL)
+ ret |= 1;
+ } else
+ ret |= mkdir(path, CACHEDIR_PERMISSIONS);
+ } else {
+ ret = 0;
+ }
+
+ g_free(p);
+ return ret;
+}
+
+gboolean
+mv(const char* old_path, const char* new_path, GError** error) try
+{
+ if (rename(old_path, new_path)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("Failed renaming %1$s to %2$s: %3$s"),
+ old_path, new_path, strerror(errno));
+ return FALSE;
+ }
+ if (chmod(new_path, 0666 & ~get_umask())) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_FILE_INVALID,
+ _("Failed setting perms on %1$s: %2$s"),
+ new_path, strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_remove_recursive_v2:
+ * @directory: A directory path
+ * @error: A #GError, or %NULL
+ *
+ * Removes a file or a directory and its contents.
+ *
+ * Returns: %FALSE if an error was set
+ **/
+gboolean
+dnf_remove_recursive_v2(const gchar *path, GError **error) try
+{
+ if (g_file_test(path, G_FILE_TEST_IS_DIR))
+ return dnf_remove_recursive(path, error);
+ else
+ return dnf_ensure_file_unlinked(path, error);
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_copy_file(const std::string & srcPath, const std::string & dstPath, GError ** error) try
+{
+ g_autoptr(GFile) src = g_file_new_for_path(srcPath.c_str());
+ g_autoptr(GFile) dest = g_file_new_for_path(dstPath.c_str());
+ return g_file_copy(src, dest,
+ static_cast<GFileCopyFlags>(G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA),
+ NULL, NULL, NULL, error);
+} CATCH_TO_GERROR(FALSE)
+
+gboolean
+dnf_copy_recursive(const std::string & srcPath, const std::string & dstPath, GError ** error) try
+{
+ struct stat info;
+ if (!stat(srcPath.c_str(), &info)) {
+ if (S_ISDIR(info.st_mode)) {
+ if (mkdir(dstPath.c_str(), info.st_mode) == -1) {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot create directory %1$s: %2$s"),
+ dstPath.c_str(), strerror(err));
+ return FALSE;
+ }
+ if (auto fd = opendir(srcPath.c_str())) {
+ gboolean ret = TRUE;
+ while (auto dent = readdir(fd)) {
+ auto name = dent->d_name;
+ if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
+ continue;
+ std::string srcItem = srcPath + "/" + name;
+ std::string dstItem = dstPath + "/" + name;
+ ret = dnf_copy_recursive(srcItem, dstItem, error);
+ if (!ret)
+ break;
+ }
+ closedir(fd);
+ return ret;
+ } else {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot open directory %1$s: %2$s"),
+ srcPath.c_str(), strerror(err));
+ return FALSE;
+ }
+ } else {
+ return dnf_copy_file(srcPath, dstPath, error);
+ }
+ } else {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot stat path %1$s: %2$s"),
+ srcPath.c_str(), strerror(err));
+ return FALSE;
+ }
+} CATCH_TO_GERROR(FALSE)
+
+/**
+ * dnf_move_recursive:
+ * @src_dir: A source directory path
+ * @dst_dir: A destination directory path
+ * @error: A #GError, or %NULL
+ *
+ * Moves a file or a directory and its contents. Native move is preferred,
+ * if not supported copy and delete fallback is used.
+ *
+ * Returns: %TRUE on successful move, %FALSE otherwise
+ **/
+gboolean
+dnf_move_recursive(const char * srcDir, const char * dstDir, GError ** error) try
+{
+ if (rename(srcDir, dstDir) == -1) {
+ if (!dnf_copy_recursive(srcDir, dstDir, error))
+ return FALSE;
+ return dnf_remove_recursive_v2(srcDir, error);
+ }
+ return TRUE;
+} CATCH_TO_GERROR(FALSE)
+
+char *
+this_username(void)
+{
+ const struct passwd *pw = getpwuid(getuid());
+ return g_strdup(pw->pw_name);
+}
+
+char *
+read_whole_file(const char *path)
+{
+ char *contents = NULL;
+ if (!g_file_get_contents (path, &contents, NULL, NULL))
+ return NULL;
+ return contents;
+}
+
+static char *
+pool_tmpdup(Pool *pool, const char *s)
+{
+ char *dup = pool_alloctmpspace(pool, strlen(s) + 1);
+ return strcpy(dup, s);
+}
+
+static Id
+running_kernel_check_path(DnfSack *sack, const char *fn)
+{
+ if (access(fn, F_OK))
+ g_debug("running_kernel_check_path(): no matching file: %s.", fn);
+
+ HyQuery q = hy_query_create_flags(sack, HY_IGNORE_EXCLUDES);
+ dnf_sack_make_provides_ready(sack);
+ q->installed();
+ hy_query_filter(q, HY_PKG_FILE, HY_EQ, fn);
+ DnfPackageSet *pset = hy_query_run_set(q);
+
+ Id id = -1;
+ id = pset->next(id);
+
+ delete pset;
+ hy_query_free(q);
+
+ return id;
+}
+
+Id
+running_kernel(DnfSack *sack)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ struct utsname un;
+
+ if (uname(&un) < 0) {
+ g_debug("uname(): %s", g_strerror(errno));
+ return -1;
+ }
+
+ char *fn = pool_tmpjoin(pool, "/boot/vmlinuz-", un.release, NULL);
+ Id kernel_id = running_kernel_check_path(sack, fn);
+
+ if (kernel_id < 0) {
+ fn = pool_tmpjoin(pool, "/lib/modules/", un.release, NULL);
+ kernel_id = running_kernel_check_path(sack, fn);
+ }
+
+ if (kernel_id >= 0)
+ g_debug("running_kernel(): %s.", id2nevra(pool, kernel_id));
+ else
+ g_debug("running_kernel(): running kernel not matched to a package.");
+ return kernel_id;
+}
+
+Repo *
+repo_by_name(DnfSack *sack, const char *name)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Repo *repo;
+ int repoid;
+
+ FOR_REPOS(repoid, repo) {
+ if (!strcmp(repo->name, name))
+ return repo;
+ }
+ return NULL;
+}
+
+HyRepo
+hrepo_by_name(DnfSack *sack, const char *name)
+{
+ Repo *repo = repo_by_name(sack, name);
+
+ if (repo)
+ return static_cast<HyRepo>(repo->appdata);
+ return NULL;
+}
+
+Id
+str2archid(Pool *pool, const char *arch)
+{
+ // originally from libsolv/examples/solv.c:str2archid()
+ Id id;
+ if (!*arch)
+ return 0;
+ id = pool_str2id(pool, arch, 0);
+ if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
+ return id;
+ if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+ return 0;
+ return id;
+}
+
+/**
+ * Return id of a package that can be upgraded with pkg.
+ *
+ * The returned package Id fulfills the following criteria:
+ * :: it is installed
+ * :: has the same name as pkg
+ * :: arch of the installed pkg is upgradable to the new pkg. In RPM world that
+ * roughly means: if both pacakges are colored (contains ELF binaries and was
+ * built with internal dependency generator), they are not upgradable to each
+ * other (i.e. i386 package can not be upgraded to x86_64, neither the other
+ * way round). If one of them is noarch and the other one colored then the
+ * pkg is upgradable (i.e. one can upgrade .noarch to .x86_64 and then again
+ * to a new version that is .noarch)
+ * :: is of lower version than pkg.
+ * :: if there are multiple packages of that name return the highest version
+ * (implying we won't claim we can upgrade an old package with an already
+ * installed version, e.g kernel).
+ *
+ * Or 0 if none such package is installed.
+ */
+Id
+what_upgrades(Pool *pool, Id pkg)
+{
+ Id l = 0, l_evr = 0;
+ Id p, pp;
+ Solvable *updated, *s = pool_id2solvable(pool, pkg);
+
+ assert(pool->installed);
+ assert(pool->whatprovides);
+ FOR_PROVIDES(p, pp, s->name) {
+ updated = pool_id2solvable(pool, p);
+ if (updated->repo != pool->installed ||
+ updated->name != s->name)
+ continue;
+ if (updated->arch != s->arch &&
+ updated->arch != ARCH_NOARCH &&
+ s->arch != ARCH_NOARCH)
+ continue;
+ if (pool_evrcmp(pool, updated->evr, s->evr, EVRCMP_COMPARE) >= 0)
+ // >= version installed, this pkg can not be used for upgrade
+ return 0;
+ if (l == 0 ||
+ pool_evrcmp(pool, updated->evr, l_evr, EVRCMP_COMPARE) > 0) {
+ l = p;
+ l_evr = updated->evr;
+ }
+ }
+ return l;
+}
+
+/**
+ * Return id of a package that can be upgraded with pkg.
+ *
+ * The returned package Id fulfills the following criteria:
+ * :: it is installed
+ * :: has the same name and arch as pkg
+ * :: is of higher version than pkg.
+ * :: if there are multiple such packages return the lowest version (so we won't
+ * claim we can downgrade a package when a lower version is already
+ * installed)
+ *
+ * Or 0 if none such package is installed.
+ */
+Id
+what_downgrades(Pool *pool, Id pkg)
+{
+ Id l = 0, l_evr = 0;
+ Id p, pp;
+ Solvable *updated, *s = pool_id2solvable(pool, pkg);
+
+ assert(pool->installed);
+ assert(pool->whatprovides);
+ FOR_PROVIDES(p, pp, s->name) {
+ updated = pool_id2solvable(pool, p);
+ if (updated->repo != pool->installed ||
+ updated->name != s->name ||
+ updated->arch != s->arch)
+ continue;
+ if (pool_evrcmp(pool, updated->evr, s->evr, EVRCMP_COMPARE) <= 0)
+ // <= version installed, this pkg can not be used for downgrade
+ return 0;
+ if (l == 0 ||
+ pool_evrcmp(pool, updated->evr, l_evr, EVRCMP_COMPARE) < 0) {
+ l = p;
+ l_evr = updated->evr;
+ }
+ }
+ return l;
+}
+
+unsigned long
+pool_get_epoch(Pool *pool, const char *evr)
+{
+ char *e, *v, *r, *endptr;
+ unsigned long epoch = 0;
+
+ pool_split_evr(pool, evr, &e, &v, &r);
+ if (e) {
+ long int converted = strtol(e, &endptr, 10);
+ assert(converted > 0);
+ assert(*endptr == '\0');
+ epoch = converted;
+ }
+
+ return epoch;
+}
+
+/**
+ * Split evr into its components.
+ *
+ * Believes blindly in 'evr' being well formed. This could be implemented
+ * without 'pool' of course but either the caller would have to provide buffers
+ * to store the split pieces, or this would call strdup (which is more expensive
+ * than the pool temp space).
+ */
+void
+pool_split_evr(Pool *pool, const char *evr_c, char **epoch, char **version,
+ char **release)
+{
+ char *evr = pool_tmpdup(pool, evr_c);
+ char *e, *v, *r;
+
+ for (e = evr + 1; *e != ':' && *e != '-' && *e != '\0'; ++e)
+ ;
+
+ if (*e == '-') {
+ *e = '\0';
+ v = evr;
+ r = e + 1;
+ e = NULL;
+ } else if (*e == '\0') {
+ v = evr;
+ e = NULL;
+ r = NULL;
+ } else { /* *e == ':' */
+ *e = '\0';
+ v = e + 1;
+ e = evr;
+ for (r = v + 1; *r != '-'; ++r)
+ assert(*r);
+ *r = '\0';
+ r++;
+ }
+ *epoch = e;
+ *version = v;
+ *release = r;
+}
+
+const char *
+id2nevra(Pool *pool, Id id)
+{
+ Solvable *s = pool_id2solvable(pool, id);
+ return pool_solvable2str(pool, s);
+}
+
+
+GPtrArray *
+packageSet2GPtrArray(libdnf::PackageSet * pset)
+{
+ if (!pset) {
+ return NULL;
+ }
+ GPtrArray *plist = hy_packagelist_create();
+
+ DnfSack * sack = pset->getSack();
+
+ Id id = -1;
+ while ((id = pset->next(id)) != -1) {
+ g_ptr_array_add(plist, dnf_package_new(sack, id));
+ }
+ return plist;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_IUTIL_H
+#define HY_IUTIL_H
+
+#include <regex.h>
+#include <solv/bitmap.h>
+#include <solv/queue.h>
+#include <solv/repo.h>
+#include <solv/rules.h>
+#include <solv/transaction.h>
+
+#include "dnf-sack.h"
+
+#define CHKSUM_BYTES 32
+
+G_BEGIN_DECLS
+
+/* crypto utils */
+int checksum_type2length(int type);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HY_NEVRA_H
+#define _HY_NEVRA_H
+
+#include "hy-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void hy_nevra_free(HyNevra nevra);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __HY_PACKAGE_INTERNAL_H
+#define __HY_PACKAGE_INTERNAL_H
+
+#include <memory>
+#include <vector>
+
+#include "hy-package.h"
+#include "dnf-sack.h"
+#include "sack/changelog.hpp"
+
+Pool *dnf_package_get_pool (DnfPackage *pkg);
+DnfSack *dnf_package_get_sack (DnfPackage *pkg);
+std::vector<libdnf::Changelog> dnf_package_get_changelogs (DnfPackage *pkg);
+
+#endif // __HY_PACKAGE_INTERNAL_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-package
+ * @short_description: Package
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * An object representing a package in the system.
+ *
+ * See also: #DnfContext
+ */
+
+#include "libdnf/utils/utils.hpp"
+
+#include <algorithm>
+#include <ctime>
+#include <stdlib.h>
+#include <solv/evr.h>
+#include <solv/pool.h>
+#include <solv/repo.h>
+#include <solv/queue.h>
+
+#include "dnf-advisory-private.hpp"
+#include "dnf-packagedelta-private.hpp"
+#include "dnf-sack-private.hpp"
+#include "hy-iutil-private.hpp"
+#include "hy-package-private.hpp"
+#include "hy-repo-private.hpp"
+#include "repo/solvable/DependencyContainer.hpp"
+#include "sack/advisorymodule.hpp"
+
+#define BLOCK_SIZE 31
+
+typedef struct
+{
+ gboolean loaded;
+ Id id;
+ DnfSack *sack;
+} DnfPackagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE(DnfPackage, dnf_package, G_TYPE_OBJECT)
+#define GET_PRIVATE(o) (static_cast<DnfPackagePrivate *>(dnf_package_get_instance_private (o)))
+
+/**
+ * dnf_package_finalize:
+ **/
+static void
+dnf_package_finalize(GObject *object)
+{
+ G_OBJECT_CLASS(dnf_package_parent_class)->finalize(object);
+}
+
+/**
+ * dnf_package_init:
+ **/
+static void
+dnf_package_init(DnfPackage *package)
+{
+}
+
+/**
+ * dnf_package_class_init:
+ **/
+static void
+dnf_package_class_init(DnfPackageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = dnf_package_finalize;
+}
+
+
+/**
+ * dnf_package_new:
+ *
+ * Creates a new #DnfPackage.
+ *
+ * Returns:(transfer full): a #DnfPackage
+ *
+ * Since: 0.7.0
+ **/
+DnfPackage *
+dnf_package_new(DnfSack *sack, Id id)
+{
+ auto pkg = DNF_PACKAGE(g_object_new(DNF_TYPE_PACKAGE, NULL));
+ auto priv = GET_PRIVATE(pkg);
+ priv->sack = sack;
+ priv->id = id;
+ return pkg;
+}
+
+
+/* internal */
+static Solvable *
+get_solvable(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ return pool_id2solvable(dnf_package_get_pool(pkg), priv->id);
+}
+
+/**
+ * dnf_package_get_pool: (skip)
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the pool used for storage.
+ *
+ * Returns: (transfer none): a %Pool
+ *
+ * Since: 0.7.0
+ */
+Pool *
+dnf_package_get_pool(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ return dnf_sack_get_pool(priv->sack);
+}
+
+static guint64
+lookup_num(DnfPackage *pkg, unsigned type)
+{
+ Solvable *s = get_solvable(pkg);
+ repo_internalize_trigger(s->repo);
+ return solvable_lookup_num(s, type, 0);
+}
+
+static DnfReldepList *
+reldeps_for(DnfPackage *pkg, Id type)
+{
+ Solvable *s = get_solvable(pkg);
+ DnfReldepList *reldeplist;
+ Queue q;
+ Id marker = -1;
+ Id solv_type = type;
+
+ if (type == SOLVABLE_REQUIRES)
+ marker = -1;
+
+ if (type == SOLVABLE_PREREQMARKER) {
+ solv_type = SOLVABLE_REQUIRES;
+ marker = 1;
+ }
+ queue_init(&q);
+ solvable_lookup_deparray(s, solv_type, &q, marker);
+
+ reldeplist = new libdnf::DependencyContainer(dnf_package_get_sack(pkg), std::move(q));
+
+ return reldeplist;
+}
+
+/**
+ * dnf_package_get_id: (skip):
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the internal ID used to identify the package in the pool.
+ *
+ * Returns: an integer, or 0 for unknown
+ *
+ * Since: 0.7.0
+ */
+Id
+dnf_package_get_id(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ return priv->id;
+}
+
+/**
+ * dnf_package_get_sack:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the package sack for the package.
+ *
+ * Returns: a #DnfSack, or %NULL
+ *
+ * Since: 0.7.0
+ */
+DnfSack *
+dnf_package_get_sack(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ return priv->sack;
+}
+
+/**
+ * dnf_package_get_identical:
+ * @pkg1: a #DnfPackage instance.
+ * @pkg2: another #DnfPackage instance.
+ *
+ * Tests two packages for equality.
+ *
+ * Returns: %TRUE if the packages are the same
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_package_get_identical(DnfPackage *pkg1, DnfPackage *pkg2)
+{
+ DnfPackagePrivate *priv1 = GET_PRIVATE(pkg1);
+ DnfPackagePrivate *priv2 = GET_PRIVATE(pkg2);
+ return priv1->id == priv2->id;
+}
+
+/**
+ * dnf_package_installed:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Tests if the package is installed.
+ *
+ * Returns: %TRUE if installed
+ *
+ * Since: 0.7.0
+ */
+gboolean
+dnf_package_installed(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ return (dnf_package_get_pool(pkg)->installed == s->repo);
+}
+
+/**
+ * dnf_package_cmp:
+ * @pkg1: a #DnfPackage instance.
+ * @pkg2: another #DnfPackage instance.
+ *
+ * Compares two packages.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_package_cmp(DnfPackage *pkg1, DnfPackage *pkg2)
+{
+ Pool *pool1 = dnf_package_get_pool(pkg1);
+ Pool *pool2 = dnf_package_get_pool(pkg2);
+ Solvable *s1 = pool_id2solvable(pool1, dnf_package_get_id(pkg1));
+ Solvable *s2 = pool_id2solvable(pool2, dnf_package_get_id(pkg2));
+ const char *str1 = pool_id2str(pool1, s1->name);
+ const char *str2 = pool_id2str(pool2, s2->name);
+ int ret = strcmp(str1, str2);
+ if (ret)
+ return ret;
+
+ ret = dnf_package_evr_cmp(pkg1, pkg2);
+ if (ret)
+ return ret;
+
+ str1 = pool_id2str(pool1, s1->arch);
+ str2 = pool_id2str(pool2, s2->arch);
+ return strcmp(str1, str2);
+}
+
+/**
+ * dnf_package_evr_cmp:
+ * @pkg1: a #DnfPackage instance.
+ * @pkg2: another #DnfPackage instance.
+ *
+ * Compares two packages, only using the EVR values.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_package_evr_cmp(DnfPackage *pkg1, DnfPackage *pkg2)
+{
+ Pool *pool1 = dnf_package_get_pool(pkg1);
+ Pool *pool2 = dnf_package_get_pool(pkg2);
+ Solvable *s1 = get_solvable(pkg1);
+ Solvable *s2 = get_solvable(pkg2);
+ const char *str1 = pool_id2str(pool1, s1->evr);
+ const char *str2 = pool_id2str(pool2, s2->evr);
+
+ return pool_evrcmp_str(dnf_package_get_pool(pkg1), str1, str2, EVRCMP_COMPARE);
+}
+
+/**
+ * dnf_package_get_location:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the location (XXX??) for the package. Note that the returned string has
+ * an undefined lifetime and may become invalid at a later time. You should copy
+ * the string if storing it into a long-lived data structure.
+ *
+ * Returns: (transfer none): string
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_location(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ repo_internalize_trigger(s->repo);
+ return solvable_get_location(s, NULL);
+}
+
+/**
+ * dnf_package_get_baseurl:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the baseurl for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_baseurl(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ return solvable_lookup_str(s, SOLVABLE_MEDIABASE);
+}
+
+/**
+ * dnf_package_get_nevra:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the package NEVRA. Note that the returned string has an undefined
+ * lifetime and may become invalid at a later time. You should copy the string
+ * if storing it into a long-lived data structure.
+ *
+ * Returns: (transfer none): a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_nevra(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ return pool_solvable2str(dnf_package_get_pool(pkg), s);
+}
+
+/**
+ * dnf_package_get_sourcerpm:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the source RPM for the package.
+ *
+ * Returns: (transfer none): a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_sourcerpm(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ repo_internalize_trigger(s->repo);
+ return solvable_lookup_sourcepkg(s);
+}
+
+/**
+ * dnf_package_get_version:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the version for the package.
+ *
+ * Returns: (transfer none): a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_version(DnfPackage *pkg)
+{
+ char *e, *v, *r;
+ pool_split_evr(dnf_package_get_pool(pkg), dnf_package_get_evr(pkg), &e, &v, &r);
+ return v;
+}
+
+/**
+ * dnf_package_get_release:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the release for the package.
+ *
+ * Returns: (transfer none): a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_release(DnfPackage *pkg)
+{
+ char *e, *v, *r;
+ pool_split_evr(dnf_package_get_pool(pkg), dnf_package_get_evr(pkg), &e, &v, &r);
+ return r;
+}
+
+/**
+ * dnf_package_get_name:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the name for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_name(DnfPackage *pkg)
+{
+ Pool *pool = dnf_package_get_pool(pkg);
+ return pool_id2str(pool, get_solvable(pkg)->name);
+}
+
+/**
+ * dnf_package_get_vendor:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the name for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.54.4
+ */
+const char *
+dnf_package_get_vendor(DnfPackage *pkg)
+{
+ Pool *pool = dnf_package_get_pool(pkg);
+ return pool_id2str(pool, get_solvable(pkg)->vendor);
+}
+
+/**
+ * dnf_package_get_packager:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_packager(DnfPackage *pkg)
+{
+ return solvable_lookup_str(get_solvable(pkg), SOLVABLE_PACKAGER);
+}
+
+/**
+ * dnf_package_get_arch:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the architecture for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_arch(DnfPackage *pkg)
+{
+ Pool *pool = dnf_package_get_pool(pkg);
+ return pool_id2str(pool, get_solvable(pkg)->arch);
+}
+
+/**
+ * dnf_package_get_chksum:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the checksum for the package.
+ *
+ * Returns: raw checksum bytes
+ *
+ * Since: 0.7.0
+ */
+const unsigned char *
+dnf_package_get_chksum(DnfPackage *pkg, int *type)
+{
+ Solvable *s = get_solvable(pkg);
+ const unsigned char* ret;
+
+ repo_internalize_trigger(s->repo);
+ ret = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, type);
+ if (ret)
+ *type = checksumt_l2h(*type);
+ return ret;
+}
+
+/**
+ * dnf_package_get_hdr_chksum:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the SHA1 checksum of the packages header.
+ * This is only set for packages in the rpmdb.
+ *
+ * Returns: raw checksum bytes
+ *
+ * Since: 0.7.0
+ */
+const unsigned char *
+dnf_package_get_hdr_chksum(DnfPackage *pkg, int *type)
+{
+ Solvable *s = get_solvable(pkg);
+ const unsigned char *ret;
+
+ repo_internalize_trigger(s->repo);
+ ret = solvable_lookup_bin_checksum(s, SOLVABLE_HDRID, type);
+ if (ret)
+ *type = checksumt_l2h(*type);
+ return ret;
+}
+
+/**
+ * dnf_package_get_description:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the description for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_description(DnfPackage *pkg)
+{
+ return solvable_lookup_str(get_solvable(pkg), SOLVABLE_DESCRIPTION);
+}
+
+/**
+ * dnf_package_get_evr:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the EVR for the package.
+ *
+ * Returns: a string
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_evr(DnfPackage *pkg)
+{
+ Pool *pool = dnf_package_get_pool(pkg);
+ return pool_id2str(pool, get_solvable(pkg)->evr);
+}
+
+/**
+ * dnf_package_get_group:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the group for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_group(DnfPackage *pkg)
+{
+ return solvable_lookup_str(get_solvable(pkg), SOLVABLE_GROUP);
+}
+
+/**
+ * dnf_package_get_license:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the license for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_license(DnfPackage *pkg)
+{
+ return solvable_lookup_str(get_solvable(pkg), SOLVABLE_LICENSE);
+}
+
+/**
+ * dnf_package_get_reponame:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the reponame for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_reponame(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ return s->repo->name;
+}
+
+/**
+ * dnf_package_get_summary:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the summary for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_summary(DnfPackage *pkg)
+{
+ Solvable *s = get_solvable(pkg);
+ return solvable_lookup_str(s, SOLVABLE_SUMMARY);
+}
+
+/**
+ * dnf_package_get_url:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the url for the package.
+ *
+ * Returns: a string, or %NULL
+ *
+ * Since: 0.7.0
+ */
+const char *
+dnf_package_get_url(DnfPackage *pkg)
+{
+ return solvable_lookup_str(get_solvable(pkg), SOLVABLE_URL);
+}
+
+/**
+ * dnf_package_get_downloadsize:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the download size for the package.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_downloadsize(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_DOWNLOADSIZE);
+}
+
+/**
+ * dnf_package_get_epoch:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the epoch for the package.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_epoch(DnfPackage *pkg)
+{
+ return pool_get_epoch(dnf_package_get_pool(pkg), dnf_package_get_evr(pkg));
+}
+
+/**
+ * dnf_package_get_hdr_end:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the header end index for the package.
+ *
+ * Returns: an index, or 0 for not known
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_hdr_end(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_HEADEREND);
+}
+
+/**
+ * dnf_package_get_installsize:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the installed size for the package.
+ *
+ * Returns: size in bytes
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_installsize(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_INSTALLSIZE);
+}
+
+/**
+ * dnf_package_get_buildtime:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the build time for the package.
+ *
+ * Returns: UNIX time
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_buildtime(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_BUILDTIME);
+}
+
+/**
+ * dnf_package_get_installtime:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the install time for the package.
+ *
+ * Returns: UNIX time
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_installtime(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_INSTALLTIME);
+}
+
+/**
+ * dnf_package_get_medianr:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the media number for the package.
+ *
+ * Returns: integer value
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_medianr(DnfPackage *pkg)
+{
+ return lookup_num(pkg, SOLVABLE_MEDIANR);
+}
+
+/**
+ * dnf_package_get_rpmdbid:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the RPMDB ID for the package.
+ *
+ * Returns: an ID, or 0 for not known
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_rpmdbid(DnfPackage *pkg)
+{
+ guint64 ret = lookup_num(pkg, RPM_RPMDBID);
+ return ret;
+}
+
+/**
+ * dnf_package_get_size:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the size for the package.
+ *
+ * Returns: size in bytes
+ *
+ * Since: 0.7.0
+ */
+guint64
+dnf_package_get_size(DnfPackage *pkg)
+{
+ unsigned type = dnf_package_installed(pkg) ? SOLVABLE_INSTALLSIZE :
+ SOLVABLE_DOWNLOADSIZE;
+ return lookup_num(pkg, type);
+}
+
+/**
+ * dnf_package_get_conflicts:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the conflicts for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_conflicts(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_CONFLICTS);
+}
+
+/**
+ * dnf_package_get_enhances:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the enhances for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_enhances(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_ENHANCES);
+}
+
+/**
+ * dnf_package_get_obsoletes:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the obsoletes for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_obsoletes(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_OBSOLETES);
+}
+
+/**
+ * dnf_package_get_provides:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the provides for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_provides(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_PROVIDES);
+}
+
+/**
+ * dnf_package_get_recommends:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the recommends for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_recommends(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_RECOMMENDS);
+}
+
+/**
+ * dnf_package_get_requires:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the requires for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_requires(DnfPackage *pkg)
+{
+
+ DnfReldepList * l = reldeps_for(pkg, SOLVABLE_REQUIRES);
+ DnfReldepList * prereq_l = reldeps_for(pkg, SOLVABLE_PREREQMARKER);
+ l->extend(prereq_l);
+ delete prereq_l;
+ return l;
+}
+
+/**
+ * dnf_package_get_requires_pre:
+ * @pkg: a #DnfPackage instance.
+ *
+ * If the package is not installed gets the Requires(pre) and Requires(post).
+ * If the package is installed it gets Requires(pre), Requires(post),
+ * Requies(preun) and Requires(postun).
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_requires_pre (DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_PREREQMARKER);
+}
+
+/**
+ * dnf_package_get_suggests:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the suggests for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_suggests(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_SUGGESTS);
+}
+
+/**
+ * dnf_package_get_supplements:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the supplements for the package.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.7.0
+ */
+DnfReldepList *
+dnf_package_get_supplements(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_SUPPLEMENTS);
+}
+
+/**
+ * dnf_package_get_prereq_ignoreinst
+ * @pkg: a #DnfPackage instance.
+ *
+ * Returns safe to remove Requires(pre) and Requires(post) dependencies
+ * of the package. Safe to remove means that the dependency is not needed by
+ * Requires(preun) nor by Requires(postun).
+ * The package must be installed otherwise empty list is returned.
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.45.1
+ */
+DnfReldepList *
+dnf_package_get_prereq_ignoreinst(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_PREREQ_IGNOREINST);
+}
+
+/**
+ * dnf_package_get_regular_requires
+ * @pkg: a #DnfPackage instance.
+ *
+ * Get the requires for the package without Requires(pre), Requires(post)
+ * Requires(preun) and Requires(postun).
+ *
+ * Returns: A #DnfReldepList
+ *
+ * Since: 0.45.1
+ */
+DnfReldepList *
+dnf_package_get_regular_requires(DnfPackage *pkg)
+{
+ return reldeps_for(pkg, SOLVABLE_REQUIRES);
+}
+
+/**
+ * dnf_package_get_files:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the files contained in the package.
+ *
+ * Returns: (transfer full): the file list
+ *
+ * Since: 0.7.0
+ */
+gchar **
+dnf_package_get_files(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ Pool *pool = dnf_package_get_pool(pkg);
+ Solvable *s = get_solvable(pkg);
+ Dataiterator di;
+ GPtrArray *ret = g_ptr_array_new();
+
+ repo_internalize_trigger(s->repo);
+ dataiterator_init(&di, pool, s->repo, priv->id, SOLVABLE_FILELIST, NULL,
+ SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
+ while (dataiterator_step(&di)) {
+ g_ptr_array_add(ret, g_strdup(di.kv.str));
+ }
+ dataiterator_free(&di);
+ g_ptr_array_add(ret, NULL);
+ return (gchar**)g_ptr_array_free (ret, FALSE);
+}
+
+/**
+ * dnf_package_get_changelogs:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the list of changelogs for the package.
+ *
+ * Returns: (transfer container) (element-type Changelog): a list
+ *
+ * Since: 0.19.1
+ */
+std::vector<libdnf::Changelog>
+dnf_package_get_changelogs(DnfPackage *pkg)
+{
+ DnfPackagePrivate *priv = GET_PRIVATE(pkg);
+ Pool *pool = dnf_package_get_pool(pkg);
+ Solvable *s = get_solvable(pkg);
+ Dataiterator di;
+ std::vector<libdnf::Changelog> changelogslist;
+
+ dataiterator_init(&di, pool, s->repo, priv->id, SOLVABLE_CHANGELOG_AUTHOR, NULL, 0);
+ dataiterator_prepend_keyname(&di, SOLVABLE_CHANGELOG);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos_parent(&di);
+ std::string author(pool_lookup_str(pool, SOLVID_POS, SOLVABLE_CHANGELOG_AUTHOR));
+ std::string text(pool_lookup_str(pool, SOLVID_POS, SOLVABLE_CHANGELOG_TEXT));
+ changelogslist.emplace_back(
+ static_cast<time_t>(pool_lookup_num(pool, SOLVID_POS, SOLVABLE_CHANGELOG_TIME, 0)),
+ std::move(author), std::move(text));
+ }
+ dataiterator_free(&di);
+ std::reverse(changelogslist.begin(), changelogslist.end());
+ return changelogslist;
+}
+
+/**
+ * dnf_package_get_advisories:
+ * @pkg: a #DnfPackage instance.
+ *
+ * Gets the list of advisories for the package.
+ *
+ * Returns: (transfer container) (element-type DnfAdvisory): a list
+ *
+ * Since: 0.7.0
+ */
+GPtrArray *
+dnf_package_get_advisories(DnfPackage *pkg, int cmp_type)
+{
+ Dataiterator di;
+ Id evr;
+ int cmp;
+ Pool *pool = dnf_package_get_pool(pkg);
+ DnfSack *sack = dnf_package_get_sack(pkg);
+ GPtrArray *advisorylist = g_ptr_array_new_with_free_func((GDestroyNotify) dnf_advisory_free);
+ Solvable *s = get_solvable(pkg);
+
+ dataiterator_init(&di, pool, 0, 0, UPDATE_COLLECTION_NAME,
+ pool_id2str(pool, s->name), SEARCH_STRING);
+ dataiterator_prepend_keyname(&di, UPDATE_COLLECTION);
+ dataiterator_prepend_keyname(&di, UPDATE_COLLECTIONLIST);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos_parent(&di);
+ if (pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_ARCH) != s->arch)
+ continue;
+ evr = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_EVR);
+ if (!evr)
+ continue;
+
+ cmp = pool_evrcmp(pool, evr, s->evr, EVRCMP_COMPARE);
+ if ((cmp > 0 && (cmp_type & HY_GT)) ||
+ (cmp < 0 && (cmp_type & HY_LT)) ||
+ (cmp == 0 && (cmp_type & HY_EQ))) {
+
+ // We need to move the di dataiterator to the start of the advisory collection
+ // so that di_advisory_collection can be initialized with SOLVID_POS because
+ // the collection it self doesn't have an id.
+ dataiterator_seek(&di, DI_SEEK_PARENT);
+ dataiterator_setpos_parent(&di);
+ dataiterator_seek(&di, DI_SEEK_PARENT);
+
+ bool isModuleCollectionApplicable = true;
+ Dataiterator di_advisory_collection;
+ dataiterator_init(&di_advisory_collection, pool, 0, SOLVID_POS, UPDATE_MODULE, 0, 0);
+ while (dataiterator_step(&di_advisory_collection)) {
+ dataiterator_setpos(&di_advisory_collection);
+ Id name = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_NAME);
+ Id stream = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_STREAM);
+ Id version = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_VERSION);
+ Id context = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_CONTEXT);
+ Id arch = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_ARCH);
+
+ libdnf::AdvisoryModule moduleAdvisory(sack, di.solvid, name, stream, version, context, arch);
+ if (moduleAdvisory.isApplicable()) {
+ isModuleCollectionApplicable = true;
+ break;
+ } else {
+ isModuleCollectionApplicable = false;
+ }
+ }
+ dataiterator_free(&di_advisory_collection);
+
+ if (isModuleCollectionApplicable) {
+ g_ptr_array_add(advisorylist, dnf_advisory_new(sack, di.solvid));
+ }
+
+ dataiterator_skip_solvable(&di);
+ }
+ }
+ dataiterator_free(&di);
+ return advisorylist;
+}
+
+/**
+ * dnf_package_get_delta_from_evr:
+ * @pkg: a #DnfPackage instance.
+ * @from_evr: the EVR string of what's installed
+ *
+ * Gets the package delta for the package given an existing EVR.
+ *
+ * Returns: a #DnfPackageDelta, or %NULL
+ *
+ * Since: 0.7.0
+ */
+DnfPackageDelta *
+dnf_package_get_delta_from_evr(DnfPackage *pkg, const char *from_evr)
+{
+ Pool *pool = dnf_package_get_pool(pkg);
+ Solvable *s = get_solvable(pkg);
+ DnfPackageDelta *delta = NULL;
+ Dataiterator di;
+ const char *name = dnf_package_get_name(pkg);
+
+ dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, name,
+ SEARCH_STRING);
+ dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO);
+ while (dataiterator_step(&di)) {
+ 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;
+ const char * base_evr = pool_id2str(pool, pool_lookup_id(pool, SOLVID_POS,
+ DELTA_BASE_EVR));
+ if (strcmp(base_evr, from_evr))
+ continue;
+
+ // we have the right delta info, set up DnfPackageDelta *and break out:
+ delta = dnf_packagedelta_new(pool);
+
+ break;
+ }
+ dataiterator_free(&di);
+
+ return delta;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __HY_PACKAGE_H
+#define __HY_PACKAGE_H
+
+#include <glib-object.h>
+#include "hy-types.h"
+#include "dnf-packagedelta.h"
+#include "dnf-reldep-list.h"
+
+G_BEGIN_DECLS
+
+#define DNF_TYPE_PACKAGE (dnf_package_get_type ())
+G_DECLARE_DERIVABLE_TYPE (DnfPackage, dnf_package, DNF, PACKAGE, GObject)
+
+struct _DnfPackageClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_dnf_reserved1) (void);
+ void (*_dnf_reserved2) (void);
+ void (*_dnf_reserved3) (void);
+ void (*_dnf_reserved4) (void);
+ void (*_dnf_reserved5) (void);
+ void (*_dnf_reserved6) (void);
+ void (*_dnf_reserved7) (void);
+ void (*_dnf_reserved8) (void);
+};
+
+DnfPackage *dnf_package_new (DnfSack *sack, Id id);
+
+gboolean dnf_package_get_identical (DnfPackage *pkg1, DnfPackage *pkg2);
+gboolean dnf_package_installed (DnfPackage *pkg);
+int dnf_package_cmp (DnfPackage *pkg1, DnfPackage *pkg2);
+int dnf_package_evr_cmp (DnfPackage *pkg1, DnfPackage *pkg2);
+
+const char *dnf_package_get_location (DnfPackage *pkg);
+const char *dnf_package_get_baseurl (DnfPackage *pkg);
+const char *dnf_package_get_nevra (DnfPackage *pkg);
+const char *dnf_package_get_sourcerpm (DnfPackage *pkg);
+const char *dnf_package_get_version (DnfPackage *pkg);
+const char *dnf_package_get_release (DnfPackage *pkg);
+
+Id dnf_package_get_id (DnfPackage *pkg);
+const char *dnf_package_get_name (DnfPackage *pkg);
+const char *dnf_package_get_vendor (DnfPackage *pkg);
+const char *dnf_package_get_arch (DnfPackage *pkg);
+const unsigned char *dnf_package_get_chksum(DnfPackage *pkg, int *type);
+const char *dnf_package_get_description(DnfPackage *pkg);
+const char *dnf_package_get_evr (DnfPackage *pkg);
+const char *dnf_package_get_group (DnfPackage *pkg);
+const char *dnf_package_get_license (DnfPackage *pkg);
+const unsigned char *dnf_package_get_hdr_chksum(DnfPackage *pkg, int *type);
+const char *dnf_package_get_packager (DnfPackage *pkg);
+const char *dnf_package_get_reponame (DnfPackage *pkg);
+const char *dnf_package_get_summary (DnfPackage *pkg);
+const char *dnf_package_get_url (DnfPackage *pkg);
+guint64 dnf_package_get_downloadsize(DnfPackage *pkg);
+guint64 dnf_package_get_epoch (DnfPackage *pkg);
+guint64 dnf_package_get_hdr_end (DnfPackage *pkg);
+guint64 dnf_package_get_installsize(DnfPackage *pkg);
+guint64 dnf_package_get_medianr (DnfPackage *pkg);
+guint64 dnf_package_get_rpmdbid (DnfPackage *pkg);
+guint64 dnf_package_get_size (DnfPackage *pkg);
+guint64 dnf_package_get_buildtime (DnfPackage *pkg);
+guint64 dnf_package_get_installtime(DnfPackage *pkg);
+
+DnfReldepList *dnf_package_get_conflicts (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_enhances (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_obsoletes (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_provides (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_recommends (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_requires (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_requires_pre (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_suggests (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_supplements (DnfPackage *pkg);
+DnfReldepList *dnf_package_get_prereq_ignoreinst(DnfPackage *pkg);
+DnfReldepList *dnf_package_get_regular_requires(DnfPackage *pkg);
+char **dnf_package_get_files (DnfPackage *pkg);
+GPtrArray *dnf_package_get_advisories (DnfPackage *pkg, int cmp_type);
+
+DnfPackageDelta *dnf_package_get_delta_from_evr(DnfPackage *pkg, const char *from_evr);
+
+G_END_DECLS
+
+#endif /* __HY_PACKAGE_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_PACKAGESET_INTERNAL_H
+#define HY_PACKAGESET_INTERNAL_H
+
+#include <solv/pooltypes.h>
+#include <solv/bitmap.h>
+
+#include "hy-packageset.h"
+
+
+#endif // HY_PACKAGESET_INTERNAL_H
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:dnf-packageset
+ * @short_description: SHORT DESCRIPTION
+ * @include: libdnf.h
+ * @stability: Unstable
+ *
+ * Long description.
+ *
+ * See also: #DnfContext
+ */
+
+
+#include "dnf-sack-private.hpp"
+#include "sack/packageset.hpp"
+
+/**
+ * dnf_packageset_new:
+ * @sack: A #DnfSack
+ *
+ * Creates a new #DnfPackageSet.
+ *
+ * Returns:(transfer full): a #DnfPackageSet *
+ *
+ * Since: 0.7.0
+ **/
+DnfPackageSet *
+dnf_packageset_new(DnfSack *sack)
+{
+ return new libdnf::PackageSet(sack);
+}
+
+/**
+ * dnf_packageset_from_bitmap: (skip):
+ * @pset: a #DnfPackageSet instance.
+ *
+ * Creates a set from a bitmap.
+ *
+ * Returns: a new #DnfPackageSet
+ *
+ * Since: 0.7.0
+ */
+DnfPackageSet *
+dnf_packageset_from_bitmap(DnfSack *sack, Map *map)
+{
+ return new libdnf::PackageSet(sack, map);
+}
+
+/**
+ * dnf_packageset_get_map: (skip):
+ * @pset: a #DnfPackageSet instance.
+ *
+ * Gets the map.
+ *
+ * Returns: A #Map, or %NULL
+ *
+ * Since: 0.7.0
+ */
+Map *
+dnf_packageset_get_map(DnfPackageSet *pset)
+{
+ return pset->getMap();
+}
+
+/**
+ * dnf_packageset_clone:
+ * @pset: a #DnfPackageSet instance.
+ *
+ * Clones the packageset.
+ *
+ * Returns: a new #DnfPackageSet
+ *
+ * Since: 0.7.0
+ */
+DnfPackageSet *
+dnf_packageset_clone(DnfPackageSet *pset)
+{
+ return new libdnf::PackageSet(*pset);
+}
+
+/**
+ * dnf_packageset_add:
+ * @pset: a #DnfPackageSet instance.
+ * @pkg: a #DnfPackage
+ *
+ * Adds a new package to the set.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.7.0
+ */
+void
+dnf_packageset_add(DnfPackageSet *pset, DnfPackage *pkg)
+{
+ pset->set(pkg);
+}
+
+/**
+ * dnf_packageset_count:
+ * @pset: a #DnfPackageSet instance.
+ *
+ * Returns the size of the set.
+ *
+ * Returns: size_t, or 0 for empty
+ *
+ * Since: 0.7.0
+ */
+size_t
+dnf_packageset_count(DnfPackageSet *pset)
+{
+ return pset->size();
+}
+
+/**
+ * dnf_packageset_has:
+ * @pset: a #DnfPackageSet instance.
+ * @pkg: a #DnfPackage.
+ *
+ * Finds out if a package is in the set.
+ *
+ * Returns: %TRUE if it exists
+ *
+ * Since: 0.7.0
+ */
+int
+dnf_packageset_has(DnfPackageSet *pset, DnfPackage *pkg)
+{
+ return pset->has(pkg);
+}
+
+void
+dnf_packageset_free(DnfPackageSet *pset)
+{
+ delete pset;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ * Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DNF_PACKAGESET_H
+#define __DNF_PACKAGESET_H
+
+#include "dnf-sack.h"
+#include "hy-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+DnfPackageSet *dnf_packageset_new (DnfSack *sack);
+void dnf_packageset_free (DnfPackageSet *pset);
+DnfPackageSet *dnf_packageset_clone (DnfPackageSet *pset);
+void dnf_packageset_add (DnfPackageSet *pset, DnfPackage *pkg);
+size_t dnf_packageset_count (DnfPackageSet *pset);
+int dnf_packageset_has (DnfPackageSet *pset, DnfPackage *pkg);
+
+DnfPackageSet *dnf_packageset_from_bitmap (DnfSack *sack, Map *m);
+Map *dnf_packageset_get_map (DnfPackageSet *pset);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(DnfPackageSet, dnf_packageset_free)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DNF_PACKAGESET_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_QUERY_INTERNAL_H
+#define HY_QUERY_INTERNAL_H
+
+// libsolv
+#include <solv/bitmap.h>
+
+// hawkey
+#include "hy-query.h"
+
+// swdb
+#include "transaction/Swdb.hpp"
+#include "goal/IdQueue.hpp"
+
+enum _match_type {
+ _HY_VOID,
+ _HY_NUM,
+ _HY_PKG,
+ _HY_RELDEP,
+ _HY_STR,
+};
+
+namespace libdnf {
+void hy_query_to_name_ordered_queue(HyQuery query, libdnf::IdQueue * samename);
+void hy_query_to_name_arch_ordered_queue(HyQuery query, libdnf::IdQueue * samename);
+}
+
+/**
+* @brief Return HySelector from HyQuery
+*
+* @param query query
+* @return HySelector
+*/
+HySelector hy_query_to_selector(HyQuery query);
+
+#endif // HY_QUERY_INTERNAL_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include "hy-goal-private.hpp"
+#include "hy-iutil-private.hpp"
+#include "hy-query-private.hpp"
+#include "hy-selector.h"
+#include "dnf-advisorypkg.h"
+#include "sack/advisorypkg.hpp"
+#include "sack/packageset.hpp"
+#include "sack/query.hpp"
+#include "repo/DependencySplitter.hpp"
+#include "repo/solvable/Dependency.hpp"
+#include "repo/solvable/DependencyContainer.hpp"
+#include "goal/Goal.hpp"
+
+Id
+query_get_index_item(HyQuery query, int index)
+{
+ return query->getIndexItem(index);
+}
+
+void
+hy_query_apply(HyQuery q)
+{
+ q->apply();
+}
+
+HyQuery
+hy_query_create(DnfSack *sack)
+{
+ return new libdnf::Query(sack);
+}
+
+HyQuery
+hy_query_create_flags(DnfSack *sack, int flags)
+{
+ libdnf::Query::ExcludeFlags newFlags = libdnf::Query::ExcludeFlags::APPLY_EXCLUDES;
+ if (flags & HY_IGNORE_EXCLUDES) {
+ newFlags = libdnf::Query::ExcludeFlags::IGNORE_EXCLUDES;
+ }
+ return new libdnf::Query(sack, newFlags);
+}
+
+HyQuery
+hy_query_from_nevra(HyNevra nevra, DnfSack *sack, bool icase)
+{
+ HyQuery query = hy_query_create(sack);
+ hy_add_filter_nevra_object(query, nevra, icase);
+ return query;
+}
+
+void
+hy_query_free(HyQuery q)
+{
+ delete q;
+}
+
+void
+hy_query_clear(HyQuery q)
+{
+ q->clear();
+}
+
+HyQuery
+hy_query_clone(HyQuery q)
+{
+ return new libdnf::Query(*q);
+}
+
+int
+hy_query_filter(HyQuery q, int keyname, int cmp_type, const char *match)
+{
+ return q->addFilter(keyname, cmp_type, match);
+}
+
+int
+hy_query_filter_empty(HyQuery q)
+{
+ return q->addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+}
+
+int
+hy_query_filter_in(HyQuery q, int keyname, int cmp_type,
+ const char **matches)
+{
+ return q->addFilter(keyname, cmp_type, matches);
+}
+
+int
+hy_query_filter_num(HyQuery q, int keyname, int cmp_type, int match)
+{
+ return q->addFilter(keyname, cmp_type, match);
+}
+
+int
+hy_query_filter_num_in(HyQuery q, int keyname, int cmp_type, int nmatches, const int *matches)
+{
+ return q->addFilter(keyname, cmp_type, nmatches, matches);
+}
+
+int
+hy_query_filter_package_in(HyQuery q, int keyname, int cmp_type,
+ DnfPackageSet *pset)
+{
+ return q->addFilter(keyname, cmp_type, pset);
+}
+
+int
+hy_query_filter_reldep(HyQuery q, int keyname, DnfReldep *reldep)
+{
+ return q->addFilter(keyname, reldep);
+}
+
+int
+hy_query_filter_reldep_in(HyQuery q, int keyname, DnfReldepList *reldeplist)
+{
+ return q->addFilter( keyname, reldeplist);
+}
+
+int
+hy_query_filter_provides(HyQuery q, int cmp_type, const char *name, const char *evr)
+{
+ libdnf::Dependency reldep(q->getSack(), name, evr, cmp_type);
+ return q->addFilter(HY_PKG_PROVIDES, &reldep);
+}
+
+int
+hy_query_filter_provides_in(HyQuery q, char **reldep_strs)
+{
+ libdnf::DependencyContainer reldeplist(q->getSack());
+ for (int i = 0; reldep_strs[i] != NULL; ++i) {
+ if (!reldeplist.addReldep(reldep_strs[i])) {
+ return DNF_ERROR_BAD_QUERY;
+ }
+ }
+ q->addFilter(HY_PKG_PROVIDES, &reldeplist);
+ return 0;
+}
+
+/**
+ * Narrows to only those installed packages for which there is a downgrading package.
+ */
+void
+hy_query_filter_downgradable(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_DOWNGRADABLE, HY_EQ, val);
+}
+
+/**
+ * Narrows to only packages downgrading installed packages.
+ */
+void
+hy_query_filter_downgrades(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_DOWNGRADES, HY_EQ, val);
+}
+
+/**
+ * Narrows to only those installed packages for which there is an updating package.
+ */
+void
+hy_query_filter_upgradable(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_UPGRADABLE, HY_EQ, val);
+}
+
+/**
+ * Narrows to only packages updating installed packages.
+ */
+void
+hy_query_filter_upgrades(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_UPGRADES, HY_EQ, val);
+}
+
+/**
+ * Narrows to only the highest version of a package per arch.
+ */
+void
+hy_query_filter_latest_per_arch(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, val);
+}
+
+/**
+ * Narrows to only the highest version of a package.
+ */
+void
+hy_query_filter_latest(HyQuery q, int val)
+{
+ q->addFilter(HY_PKG_LATEST, HY_EQ, val);
+}
+
+GPtrArray *
+hy_query_run(HyQuery q)
+{
+ return q->run();
+}
+
+DnfPackageSet *
+hy_query_run_set(HyQuery q)
+{
+ return new libdnf::PackageSet(*q->runSet());
+}
+
+/**
+ * hy_query_union:
+ * @q: a #HyQuery instance
+ * @other: other #HyQuery instance
+ *
+ * Unites query with other query (aka logical or).
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+hy_query_union(HyQuery q, HyQuery other)
+{
+ q->queryUnion(*other);
+}
+
+/**
+ * hy_query_intersection:
+ * @q: a #HyQuery instance
+ * @other: other #HyQuery instance
+ *
+ * Intersects query with other query (aka logical and).
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+hy_query_intersection(HyQuery q, HyQuery other)
+{
+ q->queryIntersection(*other);
+}
+
+/**
+ * hy_query_difference:
+ * @q: a #HyQuery instance
+ * @other: other #HyQuery instance
+ *
+ * Computes difference between query and other query (aka q and not other).
+ *
+ * Returns: Nothing.
+ *
+ * Since: 0.7.0
+ */
+void
+hy_query_difference(HyQuery q, HyQuery other)
+{
+ q->queryDifference(*other);
+}
+
+bool
+hy_query_is_empty(HyQuery query)
+{
+ return query->empty();
+}
+
+bool
+hy_query_is_applied(const HyQuery query)
+{
+ return query->getApplied();
+}
+
+const Map *
+hy_query_get_result(const HyQuery query)
+{
+ return query->getResult();
+}
+
+DnfSack *
+hy_query_get_sack(HyQuery query)
+{
+ return query->getSack();
+}
+
+void
+hy_add_filter_nevra_object(HyQuery query, HyNevra nevra, bool icase)
+{
+ query->addFilter(nevra, icase);
+}
+
+void
+hy_add_filter_extras(HyQuery query)
+{
+ query->filterExtras();
+}
+
+void
+hy_filter_recent(HyQuery query, const long unsigned int recent_limit)
+{
+ query->filterRecent(recent_limit);
+}
+
+void
+hy_filter_duplicated(HyQuery query)
+{
+ query->filterDuplicated();
+}
+
+GPtrArray *
+hy_query_get_advisory_pkgs(HyQuery query, int cmp_type)
+{
+ std::vector<libdnf::AdvisoryPkg> advisory_pkgs;
+
+ query->getAdvisoryPkgs(cmp_type, advisory_pkgs);
+ GPtrArray * advisorylist = g_ptr_array_new_full (advisory_pkgs.size(), (GDestroyNotify) dnf_advisorypkg_free);
+ for (auto & advisory_pkg : advisory_pkgs) {
+ g_ptr_array_add(advisorylist, new libdnf::AdvisoryPkg(advisory_pkg));
+ }
+ return advisorylist;
+}
+
+HySelector
+hy_query_to_selector(HyQuery query)
+{
+ HySelector selector = hy_selector_create(query->getSack());
+ DnfPackageSet *pset = hy_query_run_set(query);
+ hy_selector_pkg_set(selector, pset);
+ delete pset;
+ return selector;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_QUERY_H
+#define HY_QUERY_H
+
+#include <glib.h>
+#include <stdbool.h>
+
+
+G_BEGIN_DECLS
+
+/* hawkey */
+#include "dnf-sack.h"
+#include "dnf-types.h"
+#include "hy-types.h"
+
+enum _hy_query_flags {
+ HY_IGNORE_EXCLUDES = 1 << 0
+};
+
+#define hy_autoquery __attribute__ ((cleanup(hy_query_autofree)))
+
+void hy_query_apply(HyQuery q);
+HyQuery hy_query_create(DnfSack *sack);
+HyQuery hy_query_create_flags(DnfSack *sack, int flags);
+HyQuery hy_query_from_nevra(HyNevra nevra, DnfSack *sack, bool icase);
+void hy_query_free(HyQuery q);
+Id query_get_index_item(HyQuery query, int index);
+void hy_query_clear(HyQuery q);
+HyQuery hy_query_clone(HyQuery q);
+int hy_query_filter(HyQuery q, int keyname, int cmp_type, const char *match);
+int hy_query_filter_empty(HyQuery q);
+int hy_query_filter_in(HyQuery q, int keyname, int cmp_type,
+ const char **matches);
+int hy_query_filter_num(HyQuery q, int keyname, int cmp_type,
+ int match);
+int hy_query_filter_num_in(HyQuery q, int keyname, int cmp_type, int nmatches,
+ const int *matches);
+int hy_query_filter_package_in(HyQuery q, int keyname, int cmp_type,
+ DnfPackageSet *pset);
+int hy_query_filter_reldep(HyQuery q, int keyname, DnfReldep *reldep);
+int hy_query_filter_reldep_in(HyQuery q, int keyname,
+ DnfReldepList *reldeplist);
+int hy_query_filter_provides(HyQuery q, int cmp_type, const char *name,
+ const char *evr);
+int hy_query_filter_provides_in(HyQuery q, char **reldep_strs);
+
+/**
+ * Filter packages that are installed and have higher version than other not
+ * installed packages that are named same.
+ *
+ * NOTE: this does not guarantee packages filtered in this way are downgradable.
+ */
+void hy_query_filter_downgradable(HyQuery q, int val);
+/**
+ * Filter packages that are named same as an installed package but lower version.
+ *
+ * NOTE: this does not guarantee packages filtered in this way are installable.
+ */
+void hy_query_filter_downgrades(HyQuery q, int val);
+/**
+ * Filter packages that are installed and have lower version than other not
+ * installed packages that are named same.
+ *
+ * NOTE: this does not guarantee packages filtered in this way are upgradable.
+ */
+void hy_query_filter_upgradable(HyQuery q, int val);
+/**
+ * Filter packages that are named same as an installed package but higher version.
+ *
+ * NOTE: this does not guarantee packages filtered in this way are installable.
+ */
+void hy_query_filter_upgrades(HyQuery q, int val);
+void hy_query_filter_latest_per_arch(HyQuery q, int val);
+void hy_query_filter_latest(HyQuery q, int val);
+
+GPtrArray *hy_query_run(HyQuery q);
+DnfPackageSet *hy_query_run_set(HyQuery q);
+
+void hy_query_union(HyQuery q, HyQuery other);
+void hy_query_intersection(HyQuery q, HyQuery other);
+void hy_query_difference(HyQuery q, HyQuery other);
+bool hy_query_is_empty(HyQuery query);
+bool hy_query_is_applied(const HyQuery query);
+const Map *hy_query_get_result(const HyQuery query);
+DnfSack *hy_query_get_sack(HyQuery query);
+void hy_add_filter_nevra_object(HyQuery query, HyNevra nevra, bool icase);
+void hy_add_filter_extras(HyQuery query);
+void hy_filter_recent(HyQuery query, const long unsigned int recent_limit);
+void hy_filter_duplicated(HyQuery query);
+GPtrArray * hy_query_get_advisory_pkgs(HyQuery query, int cmp_type);
+
+static inline void
+hy_query_autofree (void *v)
+{
+ HyQuery *pp = (HyQuery*)v;
+ HyQuery query = *pp;
+ if (query)
+ hy_query_free (query);
+}
+
+G_END_DECLS
+
+#endif /* HY_QUERY_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_REPO_INTERNAL_H
+#define HY_REPO_INTERNAL_H
+
+#include "repo/Repo-private.hpp"
+
+// libsolv
+#include <solv/pooltypes.h>
+
+// hawkey
+#include "hy-iutil.h"
+#include "hy-repo.h"
+
+enum _hy_repo_repodata {
+ _HY_REPODATA_FILENAMES,
+ _HY_REPODATA_PRESTO,
+ _HY_REPODATA_UPDATEINFO,
+ _HY_REPODATA_OTHER
+};
+
+int hy_repo_transition(HyRepo repo, enum _hy_repo_state new_state);
+
+void repo_internalize_all_trigger(Pool *pool);
+void repo_internalize_trigger(Repo *r);
+void repo_update_state(HyRepo repo, enum _hy_repo_repodata which,
+ enum _hy_repo_state state);
+Id repo_get_repodata(HyRepo repo, enum _hy_repo_repodata which);
+void repo_set_repodata(HyRepo repo, enum _hy_repo_repodata which, Id repodata);
+
+namespace libdnf {
+ Repo::Impl * repoGetImpl(Repo * repo);
+}
+
+#endif // HY_REPO_INTERNAL_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_REPO_H
+#define HY_REPO_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+// hawkey
+#include "hy-types.h"
+
+enum _hy_repo_param_e {
+ HY_REPO_NAME = 0,
+ HY_REPO_MD_FN = 1,
+ HY_REPO_PRESTO_FN = 2,
+ HY_REPO_PRIMARY_FN = 3,
+ HY_REPO_FILELISTS_FN = 4,
+ HY_REPO_UPDATEINFO_FN = 5,
+ MODULES_FN = 6,
+ HY_REPO_OTHER_FN = 7
+};
+
+HyRepo hy_repo_create(const char *name);
+int hy_repo_get_cost(HyRepo repo);
+int hy_repo_get_priority(HyRepo repo);
+gboolean hy_repo_get_use_includes(HyRepo repo);
+guint hy_repo_get_n_solvables(HyRepo repo);
+void hy_repo_set_cost(HyRepo repo, int value);
+void hy_repo_set_priority(HyRepo repo, int value);
+void hy_repo_set_use_includes(HyRepo repo, gboolean enabled);
+void hy_repo_set_string(HyRepo repo, int which, const char *str_val);
+const char *hy_repo_get_string(HyRepo repo, int which);
+void hy_repo_free(HyRepo repo);
+
+G_END_DECLS
+
+#endif /* HY_REPO_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_SELECTOR_INTERNAL_H
+#define HY_SELECTOR_INTERNAL_H
+
+#include "sack/selector.hpp"
+
+static inline DnfSack *selector_sack(HySelector sltr) { return sltr->getSack(); }
+
+#endif // HY_SELECTOR_INTERNAL_H
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sack/selector.hpp"
+
+HySelector
+hy_selector_create(DnfSack *sack)
+{
+ return new libdnf::Selector(sack);
+}
+
+void
+hy_selector_free(HySelector sltr)
+{
+ delete sltr;
+}
+
+int
+hy_selector_pkg_set(HySelector sltr, DnfPackageSet *pset)
+{
+ return sltr->set(pset);
+}
+
+int
+hy_selector_set(HySelector sltr, int keyname, int cmp_type, const char *match)
+{
+ return sltr->set(keyname, cmp_type, match);
+}
+
+GPtrArray *
+hy_selector_matches(HySelector sltr)
+{
+ return sltr->matches();
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_SELECTOR_H
+#define HY_SELECTOR_H
+
+#include <glib.h>
+
+#include "dnf-sack.h"
+#include "hy-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HySelector hy_selector_create(DnfSack *sack);
+void hy_selector_free(HySelector sltr);
+int hy_selector_pkg_set(HySelector sltr, DnfPackageSet* pset);
+int hy_selector_set(HySelector sltr, int keyname, int cmp_type,
+ const char *match);
+GPtrArray *hy_selector_matches(HySelector sltr);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(HySelector, hy_selector_free, NULL)
+
+#endif
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <fnmatch.h>
+#include "dnf-reldep.h"
+#include "dnf-sack-private.hpp"
+#include "hy-subject.h"
+#include "hy-iutil-private.hpp"
+#include "nevra.hpp"
+#include "nsvcap.hpp"
+#include "hy-types.h"
+#include "hy-query-private.hpp"
+#include "hy-selector.h"
+#include "hy-util-private.hpp"
+#include "sack/query.hpp"
+#include "sack/packageset.hpp"
+
+// most specific to least
+const HyForm HY_FORMS_MOST_SPEC[] = {
+ HY_FORM_NEVRA, HY_FORM_NA, HY_FORM_NAME, HY_FORM_NEVR, HY_FORM_NEV, _HY_FORM_STOP_ };
+
+const HyModuleForm HY_MODULE_FORMS_MOST_SPEC[] = {
+ HY_MODULE_FORM_NSVCAP,
+ HY_MODULE_FORM_NSVCA,
+ HY_MODULE_FORM_NSVAP,
+ HY_MODULE_FORM_NSVA,
+ HY_MODULE_FORM_NSAP,
+ HY_MODULE_FORM_NSA,
+ HY_MODULE_FORM_NSVCP,
+ HY_MODULE_FORM_NSVP,
+ HY_MODULE_FORM_NSVC,
+ HY_MODULE_FORM_NSV,
+ HY_MODULE_FORM_NSP,
+ HY_MODULE_FORM_NS,
+ HY_MODULE_FORM_NAP,
+ HY_MODULE_FORM_NA,
+ HY_MODULE_FORM_NP,
+ HY_MODULE_FORM_N,
+ _HY_MODULE_FORM_STOP_};
+
+HySubject
+hy_subject_create(const char * pattern)
+{
+ return g_strdup(pattern);
+}
+
+void
+hy_subject_free(HySubject subject)
+{
+ g_free(subject);
+}
+
+/* Given a subject, attempt to create a query choose the first one, and update
+ * the query to try to match it.
+ *
+ * Since then, it was amended to add a `with_src` flag to avoid finding source packages
+ * from provides.
+ */
+HyQuery
+hy_subject_get_best_solution(HySubject subject, DnfSack *sack, HyForm *forms, HyNevra *out_nevra,
+ gboolean icase, gboolean with_nevra, gboolean with_provides,
+ gboolean with_filenames, gboolean with_src)
+{
+ std::unique_ptr<libdnf::Query> query(new libdnf::Query(sack, libdnf::Query::ExcludeFlags::APPLY_EXCLUDES));
+ if (!with_src)
+ query->addFilter(HY_PKG_ARCH, HY_NEQ, "src");
+ auto ret = query->filterSubject(subject, forms, icase, with_nevra, with_provides, with_filenames);
+ *out_nevra = ret.second.release();
+ return query.release();
+}
+
+
+HySelector
+hy_subject_get_best_selector(HySubject subject, DnfSack *sack, HyForm *forms, bool obsoletes,
+ const char *reponame)
+{
+ HyNevra nevra{nullptr};
+ HyQuery query = hy_subject_get_best_solution(subject, sack, forms, &nevra, FALSE, TRUE, TRUE,
+ TRUE, false);
+ if (!hy_query_is_empty(query)) {
+ if (obsoletes && nevra && nevra->hasJustName()) {
+ DnfPackageSet *pset;
+ pset = hy_query_run_set(query);
+ HyQuery query_obsoletes = hy_query_clone(query);
+ hy_query_filter_package_in(query_obsoletes, HY_PKG_OBSOLETES, HY_EQ, pset);
+ delete pset;
+ hy_query_union(query, query_obsoletes);
+ hy_query_free(query_obsoletes);
+ }
+ if (reponame != NULL) {
+ HyQuery installed_query = hy_query_clone(query);
+ installed_query->installed();
+ hy_query_filter(query, HY_PKG_REPONAME, HY_EQ, reponame);
+ hy_query_union(query, installed_query);
+ hy_query_free(installed_query);
+ }
+ }
+ delete nevra;
+ HySelector selector = hy_query_to_selector(query);
+ hy_query_free(query);
+ return selector;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_SUBJECT_H
+#define HY_SUBJECT_H
+
+#include <stdlib.h>
+#include <solv/util.h>
+#include "dnf-types.h"
+#include "hy-types.h"
+
+#include <glib.h>
+#include <stdbool.h>
+
+G_BEGIN_DECLS
+
+typedef enum _HyForm {
+ HY_FORM_NEVRA = 1,
+ HY_FORM_NEVR = 2,
+ HY_FORM_NEV = 3,
+ HY_FORM_NA = 4,
+ HY_FORM_NAME = 5,
+ _HY_FORM_STOP_ = -1
+} HyForm;
+
+typedef enum _HyModuleForm {
+ HY_MODULE_FORM_NSVCAP = 1,
+ HY_MODULE_FORM_NSVCA = 2,
+ HY_MODULE_FORM_NSVAP = 3,
+ HY_MODULE_FORM_NSVA = 4,
+ HY_MODULE_FORM_NSAP = 5,
+ HY_MODULE_FORM_NSA = 6,
+ HY_MODULE_FORM_NSVCP = 7,
+ HY_MODULE_FORM_NSVP = 8,
+ HY_MODULE_FORM_NSVC = 9,
+ HY_MODULE_FORM_NSV = 10,
+ HY_MODULE_FORM_NSP = 11,
+ HY_MODULE_FORM_NS = 12,
+ HY_MODULE_FORM_NAP = 13,
+ HY_MODULE_FORM_NA = 14,
+ HY_MODULE_FORM_NP = 15,
+ HY_MODULE_FORM_N = 16,
+ _HY_MODULE_FORM_STOP_ = -1
+} HyModuleForm;
+
+extern const HyForm HY_FORMS_MOST_SPEC[];
+extern const HyModuleForm HY_MODULE_FORMS_MOST_SPEC[];
+
+HySubject hy_subject_create(const char * pattern);
+void hy_subject_free(HySubject subject);
+
+HyQuery hy_subject_get_best_solution(HySubject subject, DnfSack *sack, HyForm *forms,
+ HyNevra *out_nevra, gboolean icase, gboolean with_nevra,
+ gboolean with_provides, gboolean with_filenames,
+ gboolean with_src);
+HyQuery hy_subject_get_best_query(HySubject subject, DnfSack *sack, gboolean with_provides);
+
+/**
+* @brief Returns HySelector with packages that represents subject. Subject can be NEVRA, provide,
+* or file provide. Additionally result can be enrich for obsoletes if subject is NEVRA with just
+* name.
+*
+* @param subject subject
+* @param sack DnfSack
+* @param forms HyForm *forms or NULL
+* @param obsoletes If TRUE, obsoletes will be added to result
+* @param reponame Id of repo
+* @param with_src Include source packages
+* @return HySelector
+*/
+HySelector hy_subject_get_best_selector(HySubject subject, DnfSack *sack, HyForm *forms,
+ bool obsoletes, const char *reponame);
+
+G_END_DECLS
+
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(HySubject, hy_subject_free, NULL)
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_TYPES_H
+#define HY_TYPES_H
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct Goal;
+ struct Nevra;
+ struct Query;
+ struct Repo;
+ struct Selector;
+}
+typedef struct libdnf::Goal * HyGoal;
+typedef struct libdnf::Nevra * HyNevra;
+typedef struct libdnf::Query * HyQuery;
+typedef struct libdnf::Repo * HyRepo;
+typedef struct libdnf::Selector * HySelector;
+#else
+typedef struct Goal * HyGoal;
+typedef struct Nevra * HyNevra;
+typedef struct Query * HyQuery;
+typedef struct _HyRepo * HyRepo;
+typedef struct Selector * HySelector;
+#endif
+
+typedef char * HySubject;
+
+typedef const unsigned char HyChecksum;
+
+typedef int (*hy_solution_callback)(HyGoal goal, void *callback_data);
+
+#define HY_SYSTEM_REPO_NAME "@System"
+#define HY_CMDLINE_REPO_NAME "@commandline"
+#define LIBDNF_MODULE_FAIL_SAFE_REPO_NAME "@modulefailsafe"
+#define HY_EXT_FILENAMES "-filenames"
+#define HY_EXT_UPDATEINFO "-updateinfo"
+#define HY_EXT_PRESTO "-presto"
+#define HY_EXT_OTHER "-other"
+
+enum _hy_key_name_e {
+ HY_PKG = 0,
+ HY_PKG_ALL = 1, /* DEPRECATED, used only to make empty query. Replaced by HY_PKG_EMPTY */
+ HY_PKG_ARCH = 2,
+ HY_PKG_CONFLICTS = 3,
+ HY_PKG_DESCRIPTION = 4,
+ HY_PKG_EPOCH = 5,
+ HY_PKG_EVR = 6,
+ HY_PKG_FILE = 7,
+ HY_PKG_NAME = 8,
+ HY_PKG_NEVRA = 9,
+ HY_PKG_OBSOLETES = 10,
+ HY_PKG_PROVIDES = 11,
+ HY_PKG_RELEASE = 12,
+ HY_PKG_REPONAME = 13,
+ HY_PKG_REQUIRES = 14,
+ HY_PKG_SOURCERPM = 15,
+ HY_PKG_SUMMARY = 16,
+ HY_PKG_URL = 17,
+ HY_PKG_VERSION = 18,
+ HY_PKG_LOCATION = 19,
+ HY_PKG_ENHANCES = 20,
+ HY_PKG_RECOMMENDS = 21,
+ HY_PKG_SUGGESTS = 22,
+ HY_PKG_SUPPLEMENTS = 23,
+ HY_PKG_ADVISORY = 24,
+ HY_PKG_ADVISORY_BUG = 25,
+ HY_PKG_ADVISORY_CVE = 26,
+ HY_PKG_ADVISORY_SEVERITY = 27,
+ HY_PKG_ADVISORY_TYPE = 28,
+ HY_PKG_DOWNGRADABLE = 29,
+ HY_PKG_DOWNGRADES = 30,
+ HY_PKG_EMPTY = 31,
+ HY_PKG_LATEST_PER_ARCH = 32,
+ HY_PKG_LATEST = 33,
+ HY_PKG_UPGRADABLE = 34,
+ HY_PKG_UPGRADES = 35,
+ /**
+ * @brief Use for strings of whole NEVRA (missing epoch is handled as epoch 0)
+ * Allowed compare types - only HY_EQ or HY_NEQ
+ */
+ HY_PKG_NEVRA_STRICT = 36,
+ HY_PKG_UPGRADES_BY_PRIORITY = 37,
+ HY_PKG_OBSOLETES_BY_PRIORITY = 38,
+ HY_PKG_LATEST_PER_ARCH_BY_PRIORITY = 39,
+};
+
+enum _hy_comparison_type_e {
+ /* part 1: flags that mix with all types */
+ HY_ICASE = 1 << 0,
+ HY_NOT = 1 << 1,
+ HY_COMPARISON_FLAG_MASK = HY_ICASE | HY_NOT,
+
+ /* part 2: comparison types that mix with each other */
+ HY_EQ = (1 << 8),
+ HY_LT = (1 << 9),
+ HY_GT = (1 << 10),
+
+ /* part 3: comparison types that only make sense for strings */
+ HY_SUBSTR = (1 << 11),
+ HY_GLOB = (1 << 12),
+
+ /* part 4: frequently used combinations */
+ HY_NEQ = HY_EQ | HY_NOT,
+
+ /* part 5: additional flags, not necessarily used for queries */
+ HY_NAME_ONLY = (1 << 16),
+
+ /* part 6: additional flags for addvisory filters*/
+ /// EQ or the first higher
+ HY_EQG = (1 << 17),
+ /// skip advisory packages with lower EVR than latest installed
+ HY_UPGRADE = (1 << 18),
+};
+
+#endif /* HY_TYPES_H */
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_UTIL_PRIVATE_HPP
+#define HY_UTIL_PRIVATE_HPP
+
+#include "hy-util.h"
+#include <glib.h>
+
+gboolean hy_is_glob_pattern(const char *pattern);
+
+/**
+ * @brief Test if pattern is file path
+ *
+ * @param pattern Strig to analyze
+ * @return gboolean Return TRUE if pattern start with "/" or pattern[0] == '*' && pattern[1] == '/'
+ */
+static inline gboolean hy_is_file_pattern(const char *pattern)
+{
+ return pattern[0] == '/' || (pattern[0] == '*' && pattern[1] == '/');
+}
+
+// see http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
+static const unsigned char _BitCountLookup[256] =
+{
+# define B2(n) n, n+1, n+1, n+2
+# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
+# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
+ B6(0), B6(1), B6(1), B6(2)
+};
+
+inline size_t
+map_count(Map *m)
+{
+ unsigned char *ti = m->map;
+ unsigned char *end = ti + m->size;
+ unsigned c = 0;
+
+ while (ti < end)
+ c += _BitCountLookup[*ti++];
+
+ return c;
+}
+
+GPtrArray *hy_packagelist_create(void);
+int hy_packagelist_has(GPtrArray *plist, DnfPackage *pkg);
+int mtime(const char *filename);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+
+#ifdef __APPLE__
+typedef int auxv_t;
+#ifndef AT_HWCAP2
+#define AT_HWCAP2 26
+#endif
+#ifndef AT_HWCAP
+#define AT_HWCAP 16
+#endif
+static unsigned long getauxval(unsigned long type)
+{
+ unsigned long ret = 0;
+ return ret;
+}
+#else
+#include <sys/auxv.h>
+#endif
+
+// hawkey
+#include "dnf-types.h"
+#include "hy-iutil-private.hpp"
+#include "nevra.hpp"
+#include "hy-package.h"
+#include "hy-subject.h"
+#include "hy-util-private.hpp"
+
+#include <memory>
+
+/* ARM specific HWCAP defines may be missing on non-ARM devices */
+#ifndef HWCAP_ARM_VFP
+#define HWCAP_ARM_VFP (1<<6)
+#endif
+#ifndef HWCAP_ARM_NEON
+#define HWCAP_ARM_NEON (1<<12)
+#endif
+
+const char *
+hy_chksum_name(int chksum_type)
+{
+ switch (chksum_type) {
+ case G_CHECKSUM_MD5:
+ return "md5";
+ case G_CHECKSUM_SHA1:
+ return "sha1";
+ case G_CHECKSUM_SHA256:
+ return "sha256";
+ case G_CHECKSUM_SHA384:
+ return "sha384";
+ case G_CHECKSUM_SHA512:
+ return "sha512";
+ default:
+ return NULL;
+ }
+}
+
+int
+hy_chksum_type(const char *chksum_name)
+{
+ if (!strcasecmp(chksum_name, "md5"))
+ return G_CHECKSUM_MD5;
+ if (!strcasecmp(chksum_name, "sha1"))
+ return G_CHECKSUM_SHA1;
+ if (!strcasecmp(chksum_name, "sha256"))
+ return G_CHECKSUM_SHA256;
+ if (!strcasecmp(chksum_name, "sha384"))
+ return G_CHECKSUM_SHA384;
+ if (!strcasecmp(chksum_name, "sha512"))
+ return G_CHECKSUM_SHA512;
+ return 0;
+}
+
+char *
+hy_chksum_str(const unsigned char *chksum, int type)
+{
+ int length = checksum_type2length(type);
+ if (length==-1)
+ return NULL;
+ char *s = static_cast<char *>(g_malloc(2 * length + 1));
+ solv_bin2hex(chksum, length, s);
+
+ return s;
+}
+
+#define MAX_ARCH_LENGTH 64
+
+int
+hy_detect_arch(char **arch)
+{
+ struct utsname un;
+
+ if (uname(&un) < 0)
+ return DNF_ERROR_FAILED;
+
+ if (!strncmp(un.machine, "armv", 4)) {
+ /* un.machine is armvXE, where X is version number and E is
+ * endianness (b or l); we need to add modifiers such as
+ * h (hardfloat), n (neon). Neon is a requirement of armv8 so
+ * as far as rpm is concerned armv8l is the equivilent of armv7hnl
+ * (or 7hnb) so we don't explicitly add 'n' for 8+ as it's expected. */
+ char endian = un.machine[strlen(un.machine)-1];
+ char *modifier = un.machine + 5;
+ while(isdigit(*modifier)) /* keep armv7, armv8, armv9, armv10, armv100, ... */
+ modifier++;
+ if (getauxval(AT_HWCAP) & HWCAP_ARM_VFP)
+ *modifier++ = 'h';
+ if ((atoi(un.machine+4) == 7) && (getauxval(AT_HWCAP) & HWCAP_ARM_NEON))
+ *modifier++ = 'n';
+ *modifier++ = endian;
+ *modifier = 0;
+ }
+#ifdef __MIPSEL__
+ if (!strcmp(un.machine, "mips"))
+ strcpy(un.machine, "mipsel");
+ else if (!strcmp(un.machine, "mips64"))
+ strcpy(un.machine, "mips64el");
+#endif
+ *arch = g_strdup(un.machine);
+ return 0;
+}
+
+#undef MAX_ARCH_LENGTH
+
+gboolean
+hy_is_glob_pattern(const char *pattern)
+{
+ return strpbrk(pattern, "*[?") != NULL;
+}
+
+int
+hy_split_nevra(const char *nevra, char **name, int *epoch,
+ char **version, char **release, char **arch)
+{
+ if (strlen(nevra) <= 0)
+ return DNF_ERROR_INTERNAL_ERROR;
+ libdnf::Nevra nevraObj;
+ if (nevraObj.parse(nevra, HY_FORM_NEVRA)) {
+ *arch = g_strdup(nevraObj.getArch().c_str());
+ *name = g_strdup(nevraObj.getName().c_str());
+ *release = g_strdup(nevraObj.getRelease().c_str());
+ *version = g_strdup(nevraObj.getVersion().c_str());
+ *epoch = nevraObj.getEpoch();
+ if (*epoch == -1)
+ *epoch = 0;
+ return 0;
+ }
+ return DNF_ERROR_INTERNAL_ERROR;
+}
+
+GPtrArray *
+hy_packagelist_create(void)
+{
+ return (GPtrArray *)g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
+}
+
+int
+hy_packagelist_has(GPtrArray *plist, DnfPackage *pkg)
+{
+ GPtrArray *a = (GPtrArray*)plist;
+ for (guint i = 0; i < a->len; ++i)
+ if (dnf_package_get_identical(pkg, static_cast<DnfPackage *>(a->pdata[i])))
+ return 1;
+ return 0;
+}
+
+int
+mtime(const char *filename)
+{
+ struct stat st;
+ stat(filename, &st);
+ return st.st_mtime;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HY_UTIL_H
+#define HY_UTIL_H
+
+#include <glib.h>
+
+#include "hy-package.h"
+#include "hy-types.h"
+
+G_BEGIN_DECLS
+
+const char *hy_chksum_name(int chksum_type);
+int hy_chksum_type(const char *chksum_name);
+char *hy_chksum_str(const unsigned char *chksum, int type);
+
+int hy_detect_arch(char **arch);
+
+int hy_split_nevra(const char *nevra, char **name, int *epoch,
+ char **version, char **release, char **arch);
+
+G_END_DECLS
+
+#endif /* HY_UTIL_H */
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/freedesktop/libdnf">
+ </gresource>
+</gresources>
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBDNF_H
+#define __LIBDNF_H
+
+#define __LIBDNF_H_INSIDE__
+
+#include <libdnf/dnf-advisory.h>
+#include <libdnf/dnf-advisorypkg.h>
+#include <libdnf/dnf-advisoryref.h>
+#include <libdnf/dnf-conf.h>
+#include <libdnf/dnf-context.h>
+#include <libdnf/dnf-goal.h>
+#include <libdnf/dnf-keyring.h>
+#include <libdnf/dnf-lock.h>
+#include <libdnf/dnf-package.h>
+#include <libdnf/dnf-packagedelta.h>
+#include <libdnf/dnf-repo-loader.h>
+#include <libdnf/dnf-repo.h>
+#include <libdnf/dnf-rpmts.h>
+#include <libdnf/dnf-sack.h>
+#include <libdnf/dnf-state.h>
+#include <libdnf/dnf-transaction.h>
+#include <libdnf/dnf-types.h>
+#include <libdnf/dnf-utils.h>
+#include <libdnf/dnf-version.h>
+
+/* In progress conversion to dnf */
+#include <libdnf/dnf-reldep-list.h>
+#include <libdnf/dnf-reldep.h>
+#include <libdnf/hy-goal.h>
+#include <libdnf/hy-nevra.h>
+#include <libdnf/hy-package.h>
+#include <libdnf/hy-packageset.h>
+#include <libdnf/hy-query.h>
+#include <libdnf/hy-repo.h>
+#include <libdnf/hy-selector.h>
+#include <libdnf/hy-subject.h>
+#include <libdnf/hy-util.h>
+
+#undef __LIBDNF_H_INSIDE__
+
+#endif /* __LIBDNF_H */
--- /dev/null
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/include
+
+Name: libdnf
+Description: Simple package manager interface using libsolv and librepo
+Version: @LIBDNF_VERSION@
+Requires: glib-2.0, librepo, rpm, sqlite3
+Requires.private: libsolv, libsolvext
+Libs: -L${libdir} -ldnf
+Cflags: -I${includedir}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "log.hpp"
+
+namespace libdnf {
+
+static NullLogger nullLogger;
+static Logger * gLogger(&nullLogger);
+
+void Log::setLogger(Logger * logger) noexcept
+{
+ if (logger)
+ gLogger = logger;
+ else
+ gLogger = &nullLogger;
+}
+
+Logger * Log::getLogger() noexcept
+{
+ return gLogger;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_LOG_HPP_
+#define _LIBDNF_LOG_HPP_
+
+#include "utils/logger.hpp"
+
+namespace libdnf {
+
+class Log {
+public:
+ static void setLogger(Logger * logger) noexcept;
+ static Logger * getLogger() noexcept;
+};
+
+}
+
+#endif // _LIBDNF_LOG_HPP_
--- /dev/null
+add_subdirectory(modulemd)
+
+set(MODULE_SOURCES
+ ${MODULE_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackageContainer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackage.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <iostream>
+#include <fnmatch.h>
+#include <numeric>
+#include <sstream>
+#include <utility>
+
+extern "C" {
+#include <solv/pool_parserpmrichdep.h>
+}
+
+#include "ModulePackage.hpp"
+#include "modulemd/ModuleProfile.hpp"
+#include "libdnf/utils/File.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/repo/Repo-private.hpp"
+#include "libdnf/sack/query.hpp"
+#include "libdnf/log.hpp"
+#include "../utils/bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+#include <memory>
+
+
+namespace libdnf {
+
+/**
+ * @brief create solvable with:
+ * Name: $name:$stream:$context
+ * Version: $version
+ * Arch: $arch (If arch is not defined, set "noarch")
+ * Provides: module($name)
+ * Provides: module($name:$stream)
+ * Summary: original_context
+ * Description: name:stream
+ */
+static void setSovable(Pool * pool, Solvable * solvable, const std::string & name,
+ const std::string & stream, const std::string & version, const std::string & context, const char * arch, const std::string & original_context)
+{
+ std::ostringstream ss;
+ // Name: $name:$stream:$context
+ ss << name << ":" << stream << ":" << context;
+ solvable_set_str(solvable, SOLVABLE_NAME, ss.str().c_str());
+ solvable_set_str(solvable, SOLVABLE_EVR, version.c_str());
+ // TODO Test can be remove when modules will be always with arch
+ solvable_set_str(solvable, SOLVABLE_ARCH, arch ? arch : "noarch");
+
+ // store original context in summary
+ solvable_set_str(solvable, SOLVABLE_SUMMARY, original_context.c_str());
+
+ // store original name:stream in description
+ ss.str(std::string());
+ ss << name << ":" << stream;
+ solvable_set_str(solvable, SOLVABLE_DESCRIPTION, ss.str().c_str());
+
+ // create Provide: module($name)
+ ss.str(std::string());
+ ss << "module(" << name << ")";
+ auto depId = pool_str2id(pool, ss.str().c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_PROVIDES, depId, -1);
+ // create Conflicts: module($name)
+ solvable_add_deparray(solvable, SOLVABLE_CONFLICTS, depId, 0);
+
+ // create Provide: module($name:$stream)
+ ss.str(std::string());
+ ss << "module(" << name << ":" << stream << ")";
+ depId = pool_str2id(pool, ss.str().c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_PROVIDES, depId, -1);
+}
+
+
+static std::pair<std::string, std::string> parsePlatform(const std::string & platform)
+{
+ auto index = platform.find(':');
+ if (index == std::string::npos) {
+ return {};
+ }
+ return make_pair(platform.substr(0,index), platform.substr(index+1));
+}
+
+ModulePackage::ModulePackage(DnfSack * moduleSack, LibsolvRepo * repo,
+ ModulemdModuleStream * mdStream, const std::string & repoID, const std::string & context)
+ : mdStream(mdStream)
+ , moduleSack(moduleSack)
+ , repoID(repoID)
+{
+ if (mdStream != nullptr) {
+ g_object_ref(mdStream);
+ }
+ Pool * pool = dnf_sack_get_pool(moduleSack);
+ id = repo_add_solvable(repo);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ std::string original_context = getContext();
+ setSovable(pool, solvable, getName(), getStream(), getVersion(), context.empty() ? original_context : context,
+ getArchCStr(), original_context);
+ createDependencies(solvable);
+ HyRepo hyRepo = static_cast<HyRepo>(repo->appdata);
+ libdnf::repoGetImpl(hyRepo)->needs_internalizing = 1;
+ dnf_sack_set_provides_not_ready(moduleSack);
+ dnf_sack_set_considered_to_update(moduleSack);
+}
+
+ModulePackage::ModulePackage(const ModulePackage & mpkg)
+ : mdStream(mpkg.mdStream)
+ , moduleSack(mpkg.moduleSack)
+ , repoID(mpkg.repoID)
+ , id(mpkg.id)
+{
+ if (mdStream != nullptr) {
+ g_object_ref(mdStream);
+ }
+}
+
+ModulePackage & ModulePackage::operator=(const ModulePackage & mpkg)
+{
+ if (this != &mpkg) {
+ if (mdStream != nullptr) {
+ g_object_unref(mdStream);
+ }
+ mdStream = mpkg.mdStream;
+ if (mdStream != nullptr) {
+ g_object_ref(mdStream);
+ }
+ moduleSack = mpkg.moduleSack;
+ repoID = mpkg.repoID;
+ id = mpkg.id;
+ }
+ return *this;
+}
+
+ModulePackage::~ModulePackage()
+{
+ if (mdStream != nullptr) {
+ g_object_unref(mdStream);
+ }
+}
+
+/**
+ * @brief Create stream dependencies based on modulemd metadata.
+ */
+void ModulePackage::createDependencies(Solvable *solvable) const
+{
+ Id depId;
+ Pool * pool = dnf_sack_get_pool(moduleSack);
+
+ for (const auto &dependency : getModuleDependencies()) {
+ for (const auto &dep_requires : dependency.getRequires()) {
+ for (const auto &singleRequires : dep_requires) {
+ auto moduleName = singleRequires.first;
+ std::vector<std::string> requiresStream;
+ for (const auto &moduleStream : singleRequires.second) {
+ if (moduleStream.find('-', 0) != std::string::npos) {
+ std::ostringstream ss;
+ ss << "module(" << moduleName << ":" << moduleStream.substr(1) << ")";
+ depId = pool_str2id(pool, ss.str().c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_CONFLICTS, depId, 0);
+ } else {
+ std::string reqFormated = "module(" + moduleName + ":" + moduleStream + ")";
+ requiresStream.push_back(std::move(reqFormated));
+ }
+ }
+ if (requiresStream.empty()) {
+ std::ostringstream ss;
+ ss << "module(" << moduleName << ")";
+ depId = pool_str2id(pool, ss.str().c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_REQUIRES, depId, -1);
+ } else if (requiresStream.size() == 1) {
+ auto & requireFormated = requiresStream[0];
+ depId = pool_str2id(pool, requireFormated.c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_REQUIRES, depId, -1);
+ } else {
+ std::ostringstream ss;
+ ss << "(";
+ ss << std::accumulate(std::next(requiresStream.begin()),
+ requiresStream.end(), requiresStream[0],
+ [](const std::string & a, const std::string & b)
+ { return a + " or " + b; });
+ ss << ")";
+ depId = pool_parserpmrichdep(pool, ss.str().c_str());
+ if (!depId)
+ throw std::runtime_error("Cannot parse module requires");
+ solvable_add_deparray(solvable, SOLVABLE_REQUIRES, depId, -1);
+ }
+ }
+ }
+ }
+}
+
+std::vector<std::string> ModulePackage::getRequires(ModulemdModuleStream * mdStream, bool removePlatform)
+{
+ std::vector<std::string> dependencies_result;
+
+ GPtrArray * cDependencies = modulemd_module_stream_v2_get_dependencies((ModulemdModuleStreamV2 *) mdStream);
+
+ for (unsigned int i = 0; i < cDependencies->len; i++) {
+ auto dependencies = static_cast<ModulemdDependencies *>(g_ptr_array_index(cDependencies, i));
+ if (!dependencies) {
+ continue;
+ }
+ char** runtimeReqModules = modulemd_dependencies_get_runtime_modules_as_strv(dependencies);
+
+ for (char **iterModule = runtimeReqModules; iterModule && *iterModule; iterModule++) {
+ char ** runtimeReqStreams = modulemd_dependencies_get_runtime_streams_as_strv(dependencies, *iterModule);
+ auto moduleName = static_cast<char *>(*iterModule);
+ if (removePlatform && strcmp(moduleName, "platform") == 0) {
+ g_strfreev(runtimeReqStreams);
+ continue;
+ }
+ std::ostringstream ss;
+ std::vector<std::string> requiredStreams;
+ for (char **iterStream = runtimeReqStreams; iterStream && *iterStream; iterStream++) {
+ requiredStreams.push_back(*iterStream);
+ }
+ if (requiredStreams.empty()) {
+ dependencies_result.emplace_back(moduleName);
+ } else {
+ std::sort(requiredStreams.begin(), requiredStreams.end());
+ ss << moduleName << ":" << "[" << *requiredStreams.begin();
+ for (auto iter = std::next(requiredStreams.begin()); iter != requiredStreams.end(); ++iter) {
+ ss << "," << *iter;
+ }
+ ss << "]";
+ dependencies_result.emplace_back(std::move(ss.str()));
+ }
+ g_strfreev(runtimeReqStreams);
+ }
+ g_strfreev(runtimeReqModules);
+ }
+
+ return dependencies_result;
+}
+
+std::string ModulePackage::getYaml() const
+{
+ ModulemdModuleIndex * i = modulemd_module_index_new();
+ modulemd_module_index_add_module_stream(i, mdStream, NULL);
+ gchar *cStrYaml = modulemd_module_index_dump_to_string(i, NULL);
+ std::string yaml = std::string(cStrYaml);
+ g_free(cStrYaml);
+ g_object_unref(i);
+ return yaml;
+}
+
+bool ModulePackage::getStaticContext() const
+{
+ return modulemd_module_stream_v2_is_static_context((ModulemdModuleStreamV2 *) mdStream);
+}
+
+/**
+ * @brief Return module $name.
+ *
+ * @return const char *
+ */
+const char * ModulePackage::getNameCStr() const
+{
+ return modulemd_module_stream_get_module_name(mdStream);
+}
+
+std::string ModulePackage::getName() const
+{
+ auto name = modulemd_module_stream_get_module_name(mdStream);
+ return name ? name : "";
+}
+
+/**
+ * @brief Return module $name:$stream:$version.
+ *
+ * @return std::string
+ */
+std::string ModulePackage::getNameStreamVersion() const
+{
+ std::ostringstream ss;
+ ss << getNameStream() << ":" << getVersion();
+ return ss.str();
+}
+
+const std::string & ModulePackage::getRepoID() const
+{
+ return repoID;
+}
+
+/**
+ * @brief Return module $stream.
+ *
+ * @return const char *
+ */
+const char * ModulePackage::getStreamCStr() const
+{
+ return modulemd_module_stream_get_stream_name(mdStream);
+}
+
+std::string ModulePackage::getStream() const
+{
+ auto stream = modulemd_module_stream_get_stream_name(mdStream);
+ return stream ? stream : "";
+}
+
+/**
+ * @brief Return module $version converted to string.
+ *
+ * @return std::string
+ */
+std::string ModulePackage::getVersion() const
+{
+ return std::to_string(modulemd_module_stream_get_version(mdStream));
+}
+
+/**
+ * @brief Return module $version.
+ *
+ * @return Long Long
+ */
+long long ModulePackage::getVersionNum() const
+{
+ return modulemd_module_stream_get_version(mdStream);
+}
+
+/**
+ * @brief Return module $context.
+ *
+ * @return std::string
+ */
+const char * ModulePackage::getContextCStr() const
+{
+ return modulemd_module_stream_get_context(mdStream);
+}
+
+std::string ModulePackage::getContext() const
+{
+ auto context = modulemd_module_stream_get_context(mdStream);
+ return context ? context : "";
+}
+
+
+/**
+ * @brief Return module $arch.
+ *
+ * @return std::string
+ */
+const char * ModulePackage::getArchCStr() const
+{
+ return modulemd_module_stream_get_arch(mdStream);
+}
+
+std::string ModulePackage::getArch() const
+{
+ auto arch = modulemd_module_stream_get_arch(mdStream);
+ return arch ? arch : "";
+}
+
+/**
+ * @brief Return module $name:$stream:$version:$context:$arch.
+ *
+ * @return std::string
+ */
+std::string ModulePackage::getFullIdentifier() const
+{
+ std::ostringstream ss;
+ ss << getName() << ":" << getStream() << ":" << getVersion() << ":" << getContext() << ":"
+ << getArch();
+ return ss.str();
+}
+
+/**
+ * @brief Return module $summary.
+ *
+ * @return std::string
+ */
+std::string ModulePackage::getSummary() const
+{
+ return modulemd_module_stream_v2_get_summary((ModulemdModuleStreamV2 *) mdStream, NULL);
+}
+
+/**
+ * @brief Return module $description.
+ *
+ * @return std::string
+ */
+std::string ModulePackage::getDescription() const
+{
+ return modulemd_module_stream_v2_get_description((ModulemdModuleStreamV2 *) mdStream, NULL);
+}
+
+/**
+ * @brief Return list of RPM NEVRAs in a module.
+ *
+ * @return std::vector<std::string>
+ */
+std::vector<std::string> ModulePackage::getArtifacts() const
+{
+ std::vector<std::string> result_rpms;
+ char ** rpms = modulemd_module_stream_v2_get_rpm_artifacts_as_strv((ModulemdModuleStreamV2 *) mdStream);
+
+ for (char **iter = rpms; iter && *iter; iter++) {
+ result_rpms.emplace_back(std::string(*iter));
+ }
+
+ g_strfreev(rpms);
+ return result_rpms;
+}
+
+/**
+ * @brief Return sorted list of RPM names that are demodularized.
+ *
+ * @return std::vector<std::string>
+ */
+std::vector<std::string> ModulePackage::getDemodularizedRpms() const
+{
+ std::vector<std::string> result_rpms;
+ char ** rpms = modulemd_module_stream_v2_get_demodularized_rpms((ModulemdModuleStreamV2 *) mdStream);
+
+ for (char **iter = rpms; iter && *iter; iter++) {
+ result_rpms.emplace_back(std::string(*iter));
+ }
+
+ g_strfreev(rpms);
+ return result_rpms;
+}
+
+std::vector<ModuleProfile>
+ModulePackage::getProfiles(const std::string &name) const
+{
+ std::vector<ModuleProfile> result_profiles;
+
+ //TODO(amatej): replace with
+ //char ** profiles = modulemd_module_stream_v2_search_profiles((ModulemdModuleStreamV2 *) mdStream, profileNameCStr);
+ char ** profiles = modulemd_module_stream_v2_get_profile_names_as_strv((ModulemdModuleStreamV2 *) mdStream);
+
+ auto profileNameCStr = name.c_str();
+ gboolean glob = hy_is_glob_pattern(profileNameCStr);
+ for (char **iter = profiles; iter && *iter; iter++) {
+ std::string keyStr = static_cast<char *>(*iter);
+ if (glob && fnmatch(profileNameCStr, static_cast<char *>(*iter), 0) == 0) {
+ result_profiles.push_back(ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, *iter)));
+ } else if (strcmp(profileNameCStr, static_cast<char *>(*iter)) == 0) {
+ result_profiles.push_back(ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, *iter)));
+ }
+ }
+
+ g_strfreev(profiles);
+ return result_profiles;
+}
+
+/* @brief Return default profiles as defined in the modulemd itself.
+ *
+ * Note this is probably not the function you want. You likely want to use
+ * ModulePackageContainer::getDefaultProfiles() instead, which sources the
+ * distro-level modulemd-defaults.
+ *
+ * Also, this function returns the first default profile, but instead we want it
+ * to return all default profiles. So supporting this properly in the future
+ * would require a new ModulePackage::getDefaultProfiles() which returns an
+ * std::vec<ModuleProfile> instead.
+ *
+ * @return ModuleProfile
+ */
+ModuleProfile
+ModulePackage::getDefaultProfile() const
+{
+ //TODO(amatej): replace with
+ //char ** profiles = modulemd_module_stream_v2_search_profiles((ModulemdModuleStreamV2 *) mdStream, profileNameCStr);
+ char ** profiles = modulemd_module_stream_v2_get_profile_names_as_strv((ModulemdModuleStreamV2 *) mdStream);
+ if (g_strv_length (profiles) == 1) {
+ return ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, profiles[0]));
+ }
+
+ for (char **iter = profiles; iter && *iter; iter++) {
+ auto profile = ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, *iter));
+ if (profile.isDefault()) {
+ return profile;
+ }
+ }
+
+ throw std::runtime_error("No default profile found for " + getFullIdentifier());
+}
+
+/**
+ * @brief Return list of ModuleProfiles.
+ *
+ * @return std::vector<ModuleProfile>
+ */
+std::vector<ModuleProfile> ModulePackage::getProfiles() const
+{
+ std::vector<ModuleProfile> result_profiles;
+ char ** profiles = modulemd_module_stream_v2_get_profile_names_as_strv((ModulemdModuleStreamV2 *) mdStream);
+
+ for (char **iter = profiles; iter && *iter; iter++) {
+ result_profiles.push_back(ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, *iter)));
+ }
+
+ g_strfreev(profiles);
+ return result_profiles;
+}
+
+/**
+ * @brief Return list of ModuleDependencies.
+ *
+ * @return std::vector<ModuleDependencies>
+ */
+std::vector<ModuleDependencies> ModulePackage::getModuleDependencies() const
+{
+ std::vector<ModuleDependencies> dependencies;
+
+ GPtrArray * cDependencies = modulemd_module_stream_v2_get_dependencies((ModulemdModuleStreamV2 *) mdStream);
+
+ for (unsigned int i = 0; i < cDependencies->len; i++) {
+ dependencies.emplace_back(static_cast<ModulemdDependencies *>(g_ptr_array_index(cDependencies, i)));
+ }
+
+ return dependencies;
+}
+
+/**
+ * @brief Add conflict with a module stream represented as a ModulePackage.
+ */
+void ModulePackage::addStreamConflict(const ModulePackage * package)
+{
+ Pool * pool = dnf_sack_get_pool(moduleSack);
+ std::ostringstream ss;
+ Solvable *solvable = pool_id2solvable(pool, id);
+
+ ss << "module(" + package->getNameStream() + ")";
+ auto depId = pool_str2id(pool, ss.str().c_str(), 1);
+ solvable_add_deparray(solvable, SOLVABLE_CONFLICTS, depId, 0);
+}
+
+static std::pair<std::string, std::string> getPlatformStream(const std::string &osReleasePath)
+{
+ auto file = File::newFile(osReleasePath);
+ file->open("r");
+ std::string line;
+ while (file->readLine(line)) {
+ if (line.find("PLATFORM_ID") != std::string::npos) {
+ auto equalCharPosition = line.find('=');
+ if (equalCharPosition == std::string::npos)
+ throw std::runtime_error("Invalid format (missing '=') of PLATFORM_ID in "
+ + osReleasePath);
+ auto startPosition = line.find('"', equalCharPosition + 1);
+ if (startPosition == std::string::npos) {
+ throw std::runtime_error("Invalid format (missing '\"' in value) of PLATFORM_ID in "
+ + osReleasePath);
+ }
+ auto colonCharPosition = line.find(':', equalCharPosition + 1);
+ if (colonCharPosition == std::string::npos) {
+ throw std::runtime_error("Invalid format (missing ':' in value) of PLATFORM_ID in "
+ + osReleasePath);
+ }
+ auto endPosition = line.find('"', colonCharPosition + 1);
+ if (endPosition == std::string::npos) {
+ throw std::runtime_error("Invalid format (missing '\"' in value) of PLATFORM_ID in "
+ + osReleasePath);
+ }
+ return make_pair(
+ line.substr(startPosition + 1, colonCharPosition - startPosition -1),
+ line.substr(colonCharPosition + 1, endPosition - colonCharPosition -1));
+ }
+ }
+ return {};
+}
+
+Id
+ModulePackage::createPlatformSolvable(DnfSack * moduleSack, const std::string & osReleasePath,
+ const std::string install_root, const char * platformModule)
+{
+ std::vector<std::string> paths;
+ paths.push_back(osReleasePath);
+ return createPlatformSolvable(nullptr, moduleSack, paths, install_root, platformModule);
+}
+
+Id
+ModulePackage::createPlatformSolvable(DnfSack * sack, DnfSack * moduleSack,
+ const std::vector<std::string> & osReleasePaths, const std::string install_root,
+ const char * platformModule)
+{
+ std::pair<std::string, std::string> parsedPlatform;
+ std::string name;
+ std::string stream;
+ if (platformModule) {
+ parsedPlatform = parsePlatform(platformModule);
+ if (!parsedPlatform.first.empty() && !parsedPlatform.second.empty()) {
+ name = parsedPlatform.first;
+ stream = parsedPlatform.second;
+ } else {
+ throw std::runtime_error(
+ tfm::format(_("Invalid format of Platform module: %s"), platformModule));
+ }
+ } else if (sack) {
+ Query baseQuery(sack);
+ baseQuery.addFilter(HY_PKG_PROVIDES, HY_EQ, "system-release");
+ baseQuery.addFilter(HY_PKG_LATEST, HY_EQ, 1);
+ baseQuery.apply();
+ Query availableQuery(baseQuery);
+ availableQuery.available();
+ auto platform = availableQuery.getStringsFromProvide("base-module");
+ auto platformSize = platform.size();
+ if (platformSize == 1) {
+ parsedPlatform = parsePlatform(*platform.begin());
+ } else if (platformSize > 1) {
+ auto logger(Log::getLogger());
+ logger->debug(_("Multiple module platforms provided by available packages\n"));
+ }
+ if (!parsedPlatform.first.empty() && !parsedPlatform.second.empty()) {
+ name = parsedPlatform.first;
+ stream = parsedPlatform.second;
+ } else {
+ baseQuery.installed();
+ platform = baseQuery.getStringsFromProvide("base-module");
+ platformSize = platform.size();
+ if (platformSize == 1) {
+ parsedPlatform = parsePlatform(*platform.begin());
+ } else if (platformSize > 1) {
+ auto logger(Log::getLogger());
+ logger->debug(_("Multiple module platforms provided by installed packages\n"));
+ }
+ if (!parsedPlatform.first.empty() && !parsedPlatform.second.empty()) {
+ name = parsedPlatform.first;
+ stream = parsedPlatform.second;
+ }
+ }
+ }
+
+ if (name.empty() || stream.empty()) {
+ for (auto & osReleasePath: osReleasePaths) {
+ std::string path;
+ if (install_root == "/") {
+ path = osReleasePath;
+ } else {
+ if (install_root.back() == '/') {
+ path = install_root.substr(0, install_root.size() -1);
+ } else {
+ path = install_root;
+ }
+ path += osReleasePath;
+ }
+ std::pair<std::string, std::string> platform;
+ try {
+ platform = getPlatformStream(path);
+ } catch (const std::exception & except) {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(_("Detection of Platform Module in %s failed: %s"),
+ osReleasePath, std::string(except.what())));
+ }
+ if (!platform.first.empty() && !platform.second.empty()) {
+ name = platform.first;
+ stream = platform.second;
+ break;
+ } else {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(_("Missing PLATFORM_ID in %s"), osReleasePath));
+ }
+ }
+ }
+ if (name.empty() || stream.empty()) {
+ throw std::runtime_error(_("No valid Platform ID detected"));
+ }
+ std::string version = "0";
+ std::string context = "00000000";
+
+ Pool * pool = dnf_sack_get_pool(moduleSack);
+ HyRepo hrepo = hy_repo_create(HY_SYSTEM_REPO_NAME);
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ LibsolvRepo *repo = repo_create(pool, HY_SYSTEM_REPO_NAME);
+ repo->appdata = hrepo;
+ repoImpl->libsolvRepo = repo;
+ repoImpl->needs_internalizing = 1;
+ Id id = repo_add_solvable(repo);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ setSovable(pool, solvable, name, stream, version, context, "noarch", context);
+ repoImpl->needs_internalizing = 1;
+ dnf_sack_set_provides_not_ready(moduleSack);
+ dnf_sack_set_considered_to_update(moduleSack);
+ pool_set_installed(pool, repo);
+ return id;
+}
+
+std::string ModulePackage::getNameStream(ModulemdModuleStream * mdStream)
+{
+ std::ostringstream ss;
+ auto name = modulemd_module_stream_get_module_name(mdStream);
+ auto stream = modulemd_module_stream_get_stream_name(mdStream);
+ ss << (name ? name : "") << ":" << (stream ? stream : "");
+ return ss.str();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_MODULEPACKAGE_HPP
+#define LIBDNF_MODULEPACKAGE_HPP
+
+#include <memory>
+#include <string>
+
+#include "libdnf/dnf-types.h"
+#include "modulemd/ModuleProfile.hpp"
+#include "modulemd/ModuleDependencies.hpp"
+#include "libdnf/repo/solvable/Package.hpp"
+#include "../goal/IdQueue.hpp"
+
+namespace libdnf {
+
+class ModulePackage // TODO inherit in future; : public Package
+{
+public:
+ ~ModulePackage();
+
+ /**
+ * @brief Create module provides based on modulemd metadata.
+ */
+ const char * getNameCStr() const;
+ std::string getName() const;
+ const char * getStreamCStr() const;
+ std::string getStream() const;
+ std::string getNameStream() const;
+ std::string getNameStreamVersion() const;
+ const std::string & getRepoID() const;
+ std::string getVersion() const;
+ long long getVersionNum() const;
+ const char * getContextCStr() const;
+ std::string getContext() const;
+ const char * getArchCStr() const;
+ std::string getArch() const;
+ std::string getFullIdentifier() const;
+
+ std::string getSummary() const;
+ std::string getDescription() const;
+
+ std::vector<std::string> getArtifacts() const;
+
+ /// Return sorted list of RPM names that are demodularized.
+ std::vector<std::string> getDemodularizedRpms() const;
+
+ bool operator==(const ModulePackage &r) const;
+ /**
+ * @brief Return profiles matched by name (which is possibly a globby pattern).
+ *
+ * @return std::vector<ModuleProfile>
+ */
+ std::vector<ModuleProfile> getProfiles(const std::string &name) const;
+ std::vector<ModuleProfile> getProfiles() const;
+ ModuleProfile getDefaultProfile() const;
+
+ std::vector<ModuleDependencies> getModuleDependencies() const;
+
+ ///DEPRECATED
+ void addStreamConflict(const ModulePackage * package);
+
+ Id getId() const { return id; };
+ std::string getYaml() const;
+
+ /**
+ * @brief Return whether context string is static. It is important for proper behaviour of modular solver
+ *
+ * @return bool
+ */
+ bool getStaticContext() const;
+ /**
+ * @brief Returns strings of modules requires ("nodejs", "nodejs:12", "nodejs:-11")
+ *
+ * @param removePlatform When true, the method will not return requires with stream "platform" (default false)
+ * @return std::vector< std::string >
+ */
+ std::vector<std::string> getRequires(bool removePlatform=false);
+
+private:
+ friend struct ModulePackageContainer;
+ friend struct ModuleMetadata;
+
+ ModulePackage(DnfSack * moduleSack, LibsolvRepo * repo,
+ ModulemdModuleStream * mdStream, const std::string & repoID, const std::string & context = {});
+
+ ModulePackage(const ModulePackage & mpkg);
+ ModulePackage & operator=(const ModulePackage & mpkg);
+
+ static Id createPlatformSolvable(DnfSack * moduleSack, const std::string &osReleasePath,
+ const std::string install_root, const char * platformModule);
+ static Id createPlatformSolvable(DnfSack * sack, DnfSack * moduleSack,
+ const std::vector<std::string> & osReleasePaths, const std::string install_root,
+ const char * platformModule);
+ void createDependencies(Solvable *solvable) const;
+ /// return vector with string requires like "nodejs:11", "nodejs", or "nodejs:-11"
+ static std::vector<std::string> getRequires(ModulemdModuleStream * mdStream, bool removePlatform);
+ static std::string getNameStream(ModulemdModuleStream * mdStream);
+
+ ModulemdModuleStream * mdStream;
+
+ // TODO: remove after inheriting from Package
+ DnfSack * moduleSack;
+ std::string repoID;
+ Id id;
+};
+
+inline bool ModulePackage::operator==(const ModulePackage &r) const
+{
+ return id == r.id && moduleSack == r.moduleSack;
+}
+
+inline std::vector<std::string> ModulePackage::getRequires(bool removePlatform)
+{
+ return getRequires(mdStream, removePlatform);
+}
+
+/**
+ * @brief Return module $name:$stream.
+ *
+ * @return std::string
+ */
+inline std::string ModulePackage::getNameStream() const
+{
+ return getNameStream(mdStream);
+}
+
+}
+
+#endif //LIBDNF_MODULEPACKAGE_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <algorithm>
+#include <set>
+#include <sstream>
+
+extern "C" {
+#include <solv/poolarch.h>
+#include <solv/solver.h>
+}
+
+#include "ModulePackageContainer.hpp"
+#include "libdnf/utils/filesystem.hpp"
+#include "libdnf/utils/utils.hpp"
+#include "libdnf/utils/File.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-query.h"
+#include "libdnf/hy-types.h"
+#include <functional>
+#include <../sack/query.hpp>
+#include "../log.hpp"
+#include "libdnf/conf/ConfigParser.hpp"
+#include "libdnf/conf/OptionStringList.hpp"
+#include "libdnf/goal/Goal.hpp"
+#include "libdnf/repo/Repo-private.hpp"
+#include "libdnf/sack/selector.hpp"
+#include "libdnf/conf/Const.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "modulemd/ModuleMetadata.hpp"
+#include "modulemd/ModuleProfile.hpp"
+
+
+namespace {
+
+/// Requires resolved goal
+/// Takes listInstalls() from goal and keep solvables with the solvable-name (<name>:<stream>:<context>) in query
+void goal2name_query(libdnf::Goal & goal, libdnf::Query & query)
+{
+ auto pool = dnf_sack_get_pool(goal.getSack());
+ auto installList = goal.listInstalls();
+ std::vector<const char *> module_names;
+ Id id = -1;
+ while ((id = installList.next(id)) != -1) {
+ Solvable * s = pool_id2solvable(pool, id);
+ const char * name = pool_id2str(pool, s->name);
+ module_names.push_back(name);
+ }
+ module_names.push_back(nullptr);
+ query.addFilter(HY_PKG_NAME, HY_EQ, module_names.data());
+}
+
+/**
+ * @brief In python => ";".join(list.sort())
+ */
+std::string concentrateVectorString(std::vector<std::string> & list)
+{
+ if (list.empty()) {
+ return {};
+ }
+ std::sort(list.begin(), list.end());
+ std::ostringstream ss;
+ ss << *list.begin();
+ for (auto require = std::next(list.begin()); require != list.end(); ++require) {
+ ss << ";" << *require;
+ }
+ return ss.str();
+}
+
+}
+
+namespace std {
+
+template<>
+struct default_delete<DIR> {
+ void operator()(DIR * ptr) noexcept { closedir(ptr); }
+};
+
+}
+
+namespace libdnf {
+
+static constexpr auto EMPTY_STREAM = "";
+static constexpr auto EMPTY_PROFILES = "";
+static constexpr auto DEFAULT_STATE = "";
+
+static const char * ENABLE_MULTIPLE_STREAM_EXCEPTION =
+_("Cannot enable multiple streams for module '%s'");
+
+static const std::string EMPTY_RESULT;
+
+static std::string
+stringFormater(std::string imput)
+{
+ return imput.empty() ? "*" : imput;
+}
+
+static ModulePackageContainer::ModuleState
+fromString(const std::string &str) {
+ if (str == "1" || str == "true" || str == "enabled")
+ return ModulePackageContainer::ModuleState::ENABLED;
+ if (str == "0" || str == "false" || str == "disabled")
+ return ModulePackageContainer::ModuleState::DISABLED;
+
+ return ModulePackageContainer::ModuleState::UNKNOWN;
+}
+
+static std::string
+toString(const ModulePackageContainer::ModuleState &state) {
+ switch (state) {
+ case ModulePackageContainer::ModuleState::ENABLED:
+ return "enabled";
+ case ModulePackageContainer::ModuleState::DISABLED:
+ return "disabled";
+ case ModulePackageContainer::ModuleState::DEFAULT:
+ return "";
+ default:
+ return "";
+ }
+}
+
+static std::string getFileContent(const std::string &filePath)
+{
+ auto yaml = File::newFile(filePath);
+
+ yaml->open("r");
+ const auto &yamlContent = yaml->getContent();
+ yaml->close();
+
+ return yamlContent;
+}
+
+/**
+ * @brief Get names in given directory with surfix ".yaml"
+ *
+ * @param dirPath p_dirPath: Directory
+ * @return std::vector< std::string > Sorted vector with all entries in directory that ends ".yaml"
+ */
+static std::vector<std::string> getYamlFilenames(const char * dirPath)
+{
+ struct dirent * ent;
+ std::unique_ptr<DIR> dir(opendir(dirPath));
+ std::vector<std::string> fileNames;
+ if (dir) {
+ DIR * dirPtr = dir.get();
+ while ((ent = readdir(dirPtr)) != NULL) {
+ auto filename = ent->d_name;
+ auto fileNameLen = strlen(filename);
+ if (fileNameLen < 10 || strcmp(filename + fileNameLen - 5, ".yaml")) {
+ continue;
+ }
+ fileNames.push_back(filename);
+ }
+ }
+ std::sort(fileNames.begin(), fileNames.end());
+ return fileNames;
+}
+
+static bool
+stringStartWithLowerComparator(const std::string & first, const std::string & pattern)
+{
+ return first.compare(0, pattern.size(), pattern) < 0;
+}
+
+class ModulePackageContainer::Impl {
+public:
+ Impl();
+ ~Impl();
+ std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType> moduleSolve(
+ const std::vector<ModulePackage *> & modules, bool debugSolver);
+ bool insert(const std::string &moduleName, const char *path);
+ std::vector<ModulePackage *> getLatestActiveEnabledModules();
+ /// Required to call after all modules v3 are in metadata
+ void addVersion2Modules();
+
+private:
+ friend struct ModulePackageContainer;
+ class ModulePersistor;
+ std::unique_ptr<ModulePersistor> persistor;
+ std::map<Id, std::unique_ptr<ModulePackage>> modules;
+ /// Internal sack with module solvables
+ /// resolveContext = <moduleContext> if moduleMdVersion > 2, else generated from requires
+ /// solvable.name = <moduleName>:<moduleStream>:<resolveContext>
+ /// solvable.evr = <moduleVersion>
+ /// solvable.arch = <moduleArch>
+ /// solvable.summary = <moduleContext>
+ /// solvable.description = <moduleName>:<moduleStream>
+ /// solvable.conflicts = module(<moduleName>)
+ DnfSack * moduleSack;
+ std::unique_ptr<PackageSet> activatedModules;
+ std::string installRoot;
+ std::string persistDir;
+ ModuleMetadata moduleMetadata;
+
+ std::map<std::string, std::string> moduleDefaults;
+ std::vector<std::tuple<LibsolvRepo *, ModulemdModuleStream *, std::string>> modulesV2;
+
+ bool isEnabled(const std::string &name, const std::string &stream);
+};
+
+class ModulePackageContainer::Impl::ModulePersistor {
+public:
+ ~ModulePersistor() = default;
+
+ const std::string & getStream(const std::string &name);
+ const std::vector<std::string> & getProfiles(const std::string &name);
+ /**
+ * @brief Can throw NoModuleException
+ */
+ const ModuleState & getState(const std::string &name);
+
+ std::map<std::string, std::string> getEnabledStreams();
+ std::vector<std::string> getDisabledModules();
+ std::map<std::string, std::string> getDisabledStreams();
+ std::vector<std::string> getResetModules();
+
+ std::map<std::string, std::string> getResetStreams();
+ std::map<std::string, std::pair<std::string, std::string>> getSwitchedStreams();
+ std::map<std::string, std::vector<std::string>> getInstalledProfiles();
+ std::map<std::string, std::vector<std::string>> getRemovedProfiles();
+
+ std::vector<std::string> getAllModuleNames();
+ bool changeStream(const std::string &name, const std::string &stream);
+ bool addProfile(const std::string &name, const std::string &profile);
+ bool removeProfile(const std::string &name, const std::string &profile);
+ bool changeState(const std::string &name, ModuleState state);
+
+ bool insert(const std::string &moduleName, const char *path);
+ void rollback();
+ void save(const std::string &installRoot, const std::string &modulesPath);
+
+private:
+ friend class Impl;
+ friend struct ModulePackageContainer;
+ struct Config {
+ std::string stream;
+ std::vector<std::string> profiles;
+ ModuleState state;
+ bool locked;
+ int streamChangesNum;
+ };
+ std::pair<ConfigParser, struct Config> & getEntry(const std::string & moduleName);
+ bool update(const std::string &name);
+ void reset(const std::string &name);
+
+ std::map<std::string, std::pair<ConfigParser, struct Config>> configs;
+};
+
+ModulePackageContainer::EnableMultipleStreamsException::EnableMultipleStreamsException(
+ const std::string & moduleName)
+: Exception(tfm::format(ENABLE_MULTIPLE_STREAM_EXCEPTION, moduleName)) {}
+
+ModulePackageContainer::ModulePackageContainer(bool allArch, std::string installRoot,
+ const char * arch, const char * persistDir) : pImpl(new Impl)
+{
+ if (allArch) {
+ dnf_sack_set_all_arch(pImpl->moduleSack, TRUE);
+ } else {
+ dnf_sack_set_arch(pImpl->moduleSack, arch, NULL);
+ }
+ if (persistDir) {
+ g_autofree gchar * dir = g_build_filename(persistDir, "modulefailsafe", NULL);
+ pImpl->persistDir = dir;
+ } else {
+ g_autofree gchar * dir = g_build_filename(installRoot.c_str(), PERSISTDIR, "modulefailsafe",
+ NULL);
+ pImpl->persistDir = dir;
+ }
+
+ pImpl->installRoot = installRoot;
+ g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(),
+ "/etc/dnf/modules.d", NULL);
+ std::unique_ptr<DIR> dir(opendir(path));
+ if (dir) {
+ struct dirent * ent;
+ /* Load "*.module" files into module persistor */
+ DIR * dirPtr = dir.get();
+ while ((ent = readdir(dirPtr)) != NULL) {
+ auto filename = ent->d_name;
+ auto fileNameLen = strlen(filename);
+ if (fileNameLen < 8 || strcmp(filename + fileNameLen - 7, ".module")) {
+ continue;
+ }
+ std::string name(filename, fileNameLen - 7);
+ pImpl->persistor->insert(name, path);
+ }
+ }
+}
+
+ModulePackageContainer::~ModulePackageContainer() = default;
+
+ModulePackageContainer::Impl::Impl() : persistor(new ModulePersistor), moduleSack(dnf_sack_new()) {}
+
+ModulePackageContainer::Impl::~Impl()
+{
+ g_object_unref(moduleSack);
+}
+
+void
+ModulePackageContainer::add(DnfSack * sack)
+{
+ Pool * pool = dnf_sack_get_pool(sack);
+ LibsolvRepo * r;
+ Id id;
+
+ FOR_REPOS(id, r) {
+ HyRepo hyRepo = static_cast<HyRepo>(r->appdata);
+ auto modules_fn = hyRepo->getMetadataPath(MD_TYPE_MODULES);
+ if (modules_fn.empty()) {
+ continue;
+ }
+ std::string yamlContent = getFileContent(modules_fn);
+ auto repoName = hyRepo->getId();
+ add(yamlContent, repoName);
+ // update defaults from repo
+ try {
+ pImpl->moduleMetadata.addMetadataFromString(yamlContent, 0);
+ } catch (const ModulePackageContainer::ResolveException & exception) {
+ throw ModulePackageContainer::ConflictException(
+ tfm::format(_("Conflicting defaults with repo '%s': %s"), repoName,
+ exception.what()));
+ }
+ }
+}
+
+void ModulePackageContainer::addDefaultsFromDisk()
+{
+ g_autofree gchar * dirPath = g_build_filename(
+ pImpl->installRoot.c_str(), "/etc/dnf/modules.defaults.d/", NULL);
+
+ for (const auto &file : filesystem::getDirContent(dirPath)) {
+ std::string yamlContent = getFileContent(file);
+ pImpl->moduleMetadata.addMetadataFromString(yamlContent, 1000);
+ }
+}
+
+void ModulePackageContainer::moduleDefaultsResolve()
+{
+ pImpl->moduleMetadata.resolveAddedMetadata();
+ pImpl->moduleDefaults = pImpl->moduleMetadata.getDefaultStreams();
+}
+
+void
+ModulePackageContainer::add(const std::string &fileContent, const std::string & repoID)
+{
+ Pool * pool = dnf_sack_get_pool(pImpl->moduleSack);
+
+ ModuleMetadata md;
+ md.addMetadataFromString(fileContent, 0);
+ md.resolveAddedMetadata();
+
+ LibsolvRepo * repo = nullptr;
+ LibsolvRepo * r;
+ Id id;
+
+ // Search whether available repo was already created
+ FOR_REPOS(id, r) {
+ if (strcmp(r->name, repoID.c_str()) == 0) {
+ repo = r;
+ }
+ }
+
+ // If not created yet, create it
+ if (!repo) {
+ Pool * pool = dnf_sack_get_pool(pImpl->moduleSack);
+ HyRepo hrepo = hy_repo_create(repoID.c_str());
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ repo = repo_create(pool, repoID.c_str());
+ repo->appdata = hrepo;
+ repoImpl->libsolvRepo = repo;
+ repoImpl->needs_internalizing = 1;
+ }
+
+ // add all modules to repository and pass ownership to module container
+ g_autofree gchar * path = g_build_filename(pImpl->installRoot.c_str(), "/etc/dnf/modules.d", NULL);
+ auto packages = md.getAllModulePackages(pImpl->moduleSack, repo, repoID, pImpl->modulesV2);
+ for(auto const& modulePackagePtr: packages) {
+ std::unique_ptr<ModulePackage> modulePackage(modulePackagePtr);
+ pImpl->modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage)));
+ pImpl->persistor->insert(modulePackagePtr->getName(), path);
+ }
+}
+
+Id
+ModulePackageContainer::addPlatformPackage(const std::string& osReleasePath,
+ const char* platformModule)
+{
+ return ModulePackage::createPlatformSolvable(pImpl->moduleSack, osReleasePath,
+ pImpl->installRoot, platformModule);
+}
+
+Id
+ModulePackageContainer::addPlatformPackage(DnfSack * sack,
+ const std::vector<std::string> & osReleasePath,
+ const char* platformModule)
+{
+ return ModulePackage::createPlatformSolvable(sack, pImpl->moduleSack, osReleasePath,
+ pImpl->installRoot, platformModule);
+}
+
+void ModulePackageContainer::createConflictsBetweenStreams()
+{
+ // TODO Use Query for filtering
+ for (const auto &iter : pImpl->modules) {
+ const auto &modulePackage = iter.second;
+
+ for (const auto &innerIter : pImpl->modules) {
+ if (modulePackage->getName() == innerIter.second->getName()
+ && modulePackage->getStream() != innerIter.second->getStream()) {
+ modulePackage->addStreamConflict(innerIter.second.get());
+ }
+ }
+ }
+}
+
+bool ModulePackageContainer::empty() const noexcept
+{
+ pImpl->addVersion2Modules();
+ return pImpl->modules.empty();
+}
+
+ModulePackage * ModulePackageContainer::getModulePackage(Id id)
+{
+ return pImpl->modules.at(id).get();
+}
+
+std::vector<ModulePackage *>
+ModulePackageContainer::requiresModuleEnablement(const PackageSet & packages)
+{
+ auto activatedModules = pImpl->activatedModules.get();
+ if (!activatedModules) {
+ return {};
+ }
+ std::vector<ModulePackage *> output;
+ Query baseQuery(packages.getSack());
+ baseQuery.addFilter(HY_PKG, HY_EQ, &packages);
+ baseQuery.apply();
+ Query testQuery(baseQuery);
+ Id moduleId = -1;
+ while ((moduleId = activatedModules->next(moduleId)) != -1) {
+ auto module = getModulePackage(moduleId);
+ if (isEnabled(module)) {
+ continue;
+ }
+ auto includeNEVRAs = module->getArtifacts();
+ std::vector<const char *> includeNEVRAsCString(includeNEVRAs.size() + 1);
+ transform(includeNEVRAs.begin(), includeNEVRAs.end(), includeNEVRAsCString.begin(),
+ std::mem_fn(&std::string::c_str));
+ testQuery.queryUnion(baseQuery);
+ testQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, includeNEVRAsCString.data());
+ if (testQuery.empty()) {
+ continue;
+ }
+ output.push_back(module);
+ }
+ return output;
+}
+
+
+/**
+ * @brief Is a ModulePackage part of an enabled stream?
+ *
+ * @return bool
+ */
+bool ModulePackageContainer::Impl::isEnabled(const std::string &name, const std::string &stream)
+{
+ try {
+ return persistor->getState(name) == ModuleState::ENABLED &&
+ persistor->getStream(name) == stream;
+ } catch (NoModuleException &) {
+ return false;
+ }
+}
+
+/**
+ * @brief Is a ModulePackage part of an enabled stream?
+ *
+ * @return bool
+ */
+bool ModulePackageContainer::isEnabled(const std::string &name, const std::string &stream)
+{
+ return pImpl->isEnabled(name, stream);
+}
+
+bool ModulePackageContainer::isEnabled(const ModulePackage * module)
+{
+ return pImpl->isEnabled(module->getName(), module->getStream());
+}
+
+/**
+ * @brief Is a ModulePackage part of a disabled module?
+ *
+ * @return bool
+ */
+bool ModulePackageContainer::isDisabled(const std::string &name)
+{
+ try {
+ return pImpl->persistor->getState(name) == ModuleState::DISABLED;
+ } catch (NoModuleException &) {
+ return false;
+ }
+}
+
+bool ModulePackageContainer::isDisabled(const ModulePackage * module)
+{
+ return isDisabled(module->getName());
+}
+
+std::vector<std::string> ModulePackageContainer::getDefaultProfiles(std::string moduleName,
+ std::string moduleStream)
+{
+ pImpl->addVersion2Modules();
+ return pImpl->moduleMetadata.getDefaultProfiles(moduleName, moduleStream);
+}
+
+const std::string & ModulePackageContainer::getDefaultStream(const std::string &name) const
+{
+ pImpl->addVersion2Modules();
+ auto it = pImpl->moduleDefaults.find(name);
+ if (it == pImpl->moduleDefaults.end()) {
+ return EMPTY_RESULT;
+ }
+ return it->second;
+}
+
+const std::string & ModulePackageContainer::getEnabledStream(const std::string &name)
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getStream(name);
+}
+
+/**
+ * @brief Mark ModulePackage as part of an enabled stream.
+ */
+bool
+ModulePackageContainer::enable(const std::string &name, const std::string & stream, const bool count)
+{
+ pImpl->addVersion2Modules();
+ if (count) {
+ pImpl->persistor->getEntry(name).second.streamChangesNum++;
+ }
+ bool changed = pImpl->persistor->changeStream(name, stream);
+ if (pImpl->persistor->changeState(name, ModuleState::ENABLED)) {
+ changed = true;
+ }
+ if (changed) {
+ auto & profiles = pImpl->persistor->getEntry(name).second.profiles;
+ profiles.clear();
+ }
+ return changed;
+}
+
+bool
+ModulePackageContainer::enable(const ModulePackage * module, const bool count)
+{
+ return enable(module->getName(), module->getStream(), count);
+}
+
+/**
+ * @brief Mark module as not part of an enabled stream.
+ */
+void ModulePackageContainer::disable(const std::string & name, const bool count)
+{
+ pImpl->addVersion2Modules();
+ if (count) {
+ pImpl->persistor->getEntry(name).second.streamChangesNum++;
+ }
+
+ pImpl->persistor->changeState(name, ModuleState::DISABLED);
+ pImpl->persistor->changeStream(name, "");
+ auto & profiles = pImpl->persistor->getEntry(name).second.profiles;
+ profiles.clear();
+}
+
+void ModulePackageContainer::disable(const ModulePackage * module, const bool count)
+{
+ disable(module->getName(), count);
+}
+
+/**
+ * @brief Reset module state so it's no longer enabled or disabled.
+ */
+void ModulePackageContainer::reset(const std::string & name, const bool count)
+{
+ pImpl->addVersion2Modules();
+ if (count) {
+ pImpl->persistor->getEntry(name).second.streamChangesNum++;
+ }
+ pImpl->persistor->changeState(name, ModuleState::UNKNOWN);
+ pImpl->persistor->changeStream(name, "");
+ auto & profiles = pImpl->persistor->getEntry(name).second.profiles;
+ profiles.clear();
+}
+
+void ModulePackageContainer::reset(const ModulePackage * module, const bool count)
+{
+ reset(module->getName(), count);
+}
+
+/**
+ * @brief Are there any changes to be saved?
+ */
+bool ModulePackageContainer::isChanged()
+{
+ if (!getEnabledStreams().empty()) {
+ return true;
+ }
+ if (!getDisabledModules().empty()) {
+ return true;
+ }
+ if (!getResetModules().empty()) {
+ return true;
+ }
+ if (!getSwitchedStreams().empty()) {
+ return true;
+ }
+ if (!getInstalledProfiles().empty()) {
+ return true;
+ }
+ if (!getRemovedProfiles().empty()) {
+ return true;
+ }
+ return false;
+}
+
+void ModulePackageContainer::install(const std::string &name, const std::string &stream,
+ const std::string &profile)
+{
+ pImpl->addVersion2Modules();
+ for (const auto &iter : pImpl->modules) {
+ auto modulePackage = iter.second.get();
+ if (modulePackage->getName() == name && modulePackage->getStream() == stream) {
+ install(modulePackage, profile);
+ }
+ }
+}
+
+void ModulePackageContainer::install(const ModulePackage * module, const std::string &profile)
+{
+ if (pImpl->persistor->getStream(module->getName()) == module->getStream())
+ pImpl->persistor->addProfile(module->getName(), profile);
+}
+
+void ModulePackageContainer::uninstall(const std::string &name, const std::string &stream,
+ const std::string &profile)
+{
+ pImpl->addVersion2Modules();
+ for (const auto &iter : pImpl->modules) {
+ auto modulePackage = iter.second.get();
+ if (modulePackage->getName() == name && modulePackage->getStream() == stream) {
+ uninstall(modulePackage, profile);
+ }
+ }
+}
+
+void ModulePackageContainer::uninstall(const ModulePackage * module, const std::string &profile)
+{
+ if (pImpl->persistor->getStream(module->getName()) == module->getStream())
+ pImpl->persistor->removeProfile(module->getName(), profile);
+}
+
+std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType>
+ModulePackageContainer::Impl::moduleSolve(const std::vector<ModulePackage *> & modules,
+ bool debugSolver)
+{
+ if (modules.empty()) {
+ activatedModules.reset();
+ return std::make_pair(std::vector<std::vector<std::string>>(),
+ ModulePackageContainer::ModuleErrorType::NO_ERROR);
+ }
+ dnf_sack_recompute_considered(moduleSack);
+ dnf_sack_make_provides_ready(moduleSack);
+ Goal goal(moduleSack);
+ Goal goalWeak(moduleSack);
+ for (const auto &module : modules) {
+ std::ostringstream ss;
+ auto name = module->getName();
+ ss << "module(" << name << ":" << module->getStream() << ")";
+ Selector selector(moduleSack);
+ bool optional = persistor->getState(name) == ModuleState::DEFAULT;
+ selector.set(HY_PKG_PROVIDES, HY_EQ, ss.str().c_str());
+ goal.install(&selector, optional);
+ goalWeak.install(&selector, true);
+ }
+ auto ret = goal.run(static_cast<DnfGoalActions>(DNF_IGNORE_WEAK | DNF_FORCE_BEST));
+ if (debugSolver) {
+ goal.writeDebugdata("debugdata/modules");
+ }
+ std::vector<std::vector<std::string>> problems;
+ auto problemType = ModulePackageContainer::ModuleErrorType::NO_ERROR;
+ if (ret) {
+ // Goal run ignor problem in defaults
+ problems = goal.describeAllProblemRules(false);
+ ret = goal.run(DNF_FORCE_BEST);
+ if (ret) {
+ // Goal run ignor problem in defaults and in latest
+ ret = goal.run(DNF_NONE);
+ if (ret) {
+ // Conflicting modules has to be removed otherwice it could result than one of them will
+ // be active
+ auto conflictingPkgs = goal.listConflictPkgs(DNF_PACKAGE_STATE_AVAILABLE);
+ dnf_sack_add_excludes(moduleSack, conflictingPkgs.get());
+ ret = goalWeak.run(DNF_NONE);
+ if (ret) {
+ auto logger(Log::getLogger());
+ logger->critical("Modularity filtering totally broken\n");
+ problemType = ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULES;
+ activatedModules.reset();
+ } else {
+ problemType = ModulePackageContainer::ModuleErrorType::ERROR;
+ Query query(moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ goal2name_query(goalWeak, query);
+ activatedModules.reset(new PackageSet(*query.runSet()));
+ }
+ return make_pair(problems, problemType);
+ }
+ problemType = ModulePackageContainer::ModuleErrorType::ERROR_IN_LATEST;
+ } else {
+ problemType = ModulePackageContainer::ModuleErrorType::ERROR_IN_DEFAULTS;
+ }
+ }
+ Query query(moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ goal2name_query(goal, query);
+ activatedModules.reset(new PackageSet(*query.runSet()));
+ return make_pair(problems, problemType);
+}
+
+std::vector<ModulePackage *>
+ModulePackageContainer::query(Nsvcap& moduleNevra)
+{
+ return query(moduleNevra.getName(), moduleNevra.getStream(), moduleNevra.getVersion(),
+ moduleNevra.getContext(), moduleNevra.getArch());
+}
+
+std::vector<ModulePackage *>
+ModulePackageContainer::query(std::string subject)
+{
+ pImpl->addVersion2Modules();
+ // Alternatively a search using module provides could be performed
+ std::vector<ModulePackage *> result;
+ Query query(pImpl->moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ // platform modules are installed and not in modules std::Map.
+ query.available();
+ std::ostringstream ss;
+ ss << subject << "*";
+ query.addFilter(HY_PKG_NAME, HY_GLOB, ss.str().c_str());
+ auto pset = query.runSet();
+ Id moduleId = -1;
+ while ((moduleId = pset->next(moduleId)) != -1) {
+ result.push_back(pImpl->modules.at(moduleId).get());
+ }
+ return result;
+}
+
+std::vector<ModulePackage *>
+ModulePackageContainer::query(std::string name, std::string stream, std::string version,
+ std::string context, std::string arch)
+{
+ pImpl->addVersion2Modules();
+ // Alternatively a search using module provides could be performed
+ std::vector<ModulePackage *> result;
+ Query query(pImpl->moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ // platform modules are installed and not in modules std::Map.
+ query.available();
+ if (!name.empty() || !stream.empty()) {
+ std::ostringstream ss;
+ ss << stringFormater(name) << ":" << stringFormater(stream);
+ query.addFilter(HY_PKG_DESCRIPTION, HY_GLOB, ss.str().c_str());
+ }
+ if (!context.empty()) {
+ query.addFilter(HY_PKG_SUMMARY, HY_GLOB, context.c_str());
+ }
+ if (!arch.empty()) {
+ query.addFilter(HY_PKG_ARCH, HY_GLOB, arch.c_str());
+ }
+ if (!version.empty()) {
+ query.addFilter(HY_PKG_VERSION, HY_GLOB, version.c_str());
+ }
+ auto pset = query.runSet();
+ Id moduleId = -1;
+ while ((moduleId = pset->next(moduleId)) != -1) {
+ result.push_back(pImpl->modules.at(moduleId).get());
+ }
+ return result;
+}
+
+void ModulePackageContainer::enableDependencyTree(std::vector<ModulePackage *> & modulePackages)
+{
+ if (!pImpl->activatedModules) {
+ return;
+ }
+ PackageSet toEnable(pImpl->moduleSack);
+ PackageSet enabled(pImpl->moduleSack);
+ for (auto & modulePackage: modulePackages) {
+ if (!isModuleActive(modulePackage)) {
+ continue;
+ }
+ Query query(pImpl->moduleSack);
+ query.addFilter(HY_PKG, HY_EQ, pImpl->activatedModules.get());
+ auto pkg = dnf_package_new(pImpl->moduleSack, modulePackage->getId());
+ auto dep_requires = dnf_package_get_requires(pkg);
+ query.addFilter(HY_PKG_PROVIDES, dep_requires);
+ auto set = query.runSet();
+ toEnable += *set;
+ delete dep_requires;
+ g_object_unref(pkg);
+ enable(modulePackage);
+ enabled.set(modulePackage->getId());
+ }
+ toEnable -= enabled;
+ while (!toEnable.empty()) {
+ Id moduleId = -1;
+ while ((moduleId = toEnable.next(moduleId)) != -1) {
+ enable(pImpl->modules.at(moduleId).get());
+ enabled.set(moduleId);
+ Query query(pImpl->moduleSack);
+ query.addFilter(HY_PKG, HY_EQ, pImpl->activatedModules.get());
+ query.addFilter(HY_PKG, HY_NEQ, &enabled);
+ auto pkg = dnf_package_new(pImpl->moduleSack, moduleId);
+ auto dep_requires = dnf_package_get_requires(pkg);
+ query.addFilter(HY_PKG_PROVIDES, dep_requires);
+ auto set = query.runSet();
+ toEnable += *set;
+ delete dep_requires;
+ g_object_unref(pkg);
+ }
+ toEnable -= enabled;
+ }
+}
+
+ModulePackageContainer::ModuleState
+ModulePackageContainer::getModuleState(const std::string& name)
+{
+ try {
+ return pImpl->persistor->getState(name);
+ } catch (NoModuleException &) {
+ return ModuleState::UNKNOWN;
+ }
+}
+
+ModulePackage * ModulePackageContainer::getLatestModule(std::vector<ModulePackage *> modulePackages, bool activeOnly)
+{
+ ModulePackage * latest = nullptr;
+ for (ModulePackage * module: modulePackages) {
+ if (!activeOnly || isModuleActive(module->getId())) {
+ if (!latest) {
+ latest = module;
+ } else {
+ if (module->getVersionNum() > latest->getVersionNum()) {
+ latest = module;
+ }
+ }
+ }
+ }
+
+ return latest;
+}
+
+std::set<std::string> ModulePackageContainer::getInstalledPkgNames()
+{
+ pImpl->addVersion2Modules();
+ auto moduleNames = pImpl->persistor->getAllModuleNames();
+ std::set<std::string> pkgNames;
+ for (auto & moduleName: moduleNames) {
+ auto stream = getEnabledStream(moduleName);
+ if (stream.empty()) {
+ continue;
+ }
+ auto profilesInstalled = getInstalledProfiles(moduleName);
+ if (profilesInstalled.empty()) {
+ continue;
+ }
+ std::string nameStream(moduleName);
+ nameStream += ":";
+ nameStream += stream;
+ auto modules = query(nameStream);
+ const ModulePackage * latest = getLatestModule(modules, true);
+ if (!latest) {
+ latest = getLatestModule(modules, false);
+ }
+ if (!latest) {
+ continue;
+ }
+ for (auto & profile: profilesInstalled) {
+ auto profiles = latest->getProfiles(profile);
+ for (auto & profile: profiles) {
+ auto pkgs = profile.getContent();
+ for (auto pkg: pkgs) {
+ pkgNames.insert(pkg);
+ }
+ }
+ }
+ }
+ return pkgNames;
+}
+
+std::string
+ModulePackageContainer::getReport()
+{
+ std::string report;
+
+ auto installedProfiles = getInstalledProfiles();
+ if (!installedProfiles.empty()) {
+ report += _("Installing module profiles:\n");
+ for (auto & item: installedProfiles) {
+ for (auto & profile:item.second) {
+ report += " ";
+ report += item.first;
+ report += ":";
+ report += profile;
+ report += "\n";
+ }
+ }
+ report += "\n";
+ }
+
+ auto removedProfiles = getRemovedProfiles();
+ if (!removedProfiles.empty()) {
+ report += _("Disabling module profiles:\n");
+ for (auto & item: removedProfiles) {
+ for (auto & profile:item.second) {
+ report += " ";
+ report += item.first;
+ report += ":";
+ report += profile;
+ report += "\n";
+ }
+ }
+ report += "\n";
+ }
+
+ auto enabled = getEnabledStreams();
+ if (!enabled.empty()) {
+ report += _("Enabling module streams:\n");
+ for (auto & item: enabled) {
+ report += " ";
+ report += item.first;
+ report += ":";
+ report += item.second;
+ report += "\n";
+ }
+ report += "\n";
+ }
+
+ auto switchedStreams = getSwitchedStreams();
+ if (!switchedStreams.empty()) {
+ std::string switchedReport;
+ switchedReport += _("Switching module streams:\n");
+ for (auto & item: switchedStreams) {
+ switchedReport += " ";
+ switchedReport += item.first;
+ switchedReport += ":";
+ switchedReport += item.second.first;
+ switchedReport += " > ";
+ switchedReport += item.first;
+ switchedReport += ":";
+ switchedReport += item.second.second;
+ switchedReport += "\n";
+ }
+ report += switchedReport;
+ report += "\n";
+ }
+
+ auto disabled = getDisabledModules();
+ if (!disabled.empty()) {
+ report += _("Disabling modules:\n");
+ for (auto & name: disabled) {
+ report += " ";
+ report += name;
+ report += "\n";
+ }
+ report += "\n";
+ }
+
+ auto reset = getResetModules();
+ if (!reset.empty()) {
+ report += _("Resetting modules:\n");
+ for (auto & name: reset) {
+ report += " ";
+ report += name;
+ report += "\n";
+ }
+ report += "\n";
+ }
+ return report;
+}
+
+static bool
+modulePackageLatestPerRepoSorter(DnfSack * sack, const ModulePackage * first, const ModulePackage * second)
+{
+ if (first->getRepoID() != second->getRepoID())
+ return first->getRepoID() < second->getRepoID();
+ int cmp = g_strcmp0(first->getNameCStr(), second->getNameCStr());
+ if (cmp != 0)
+ return cmp < 0;
+ cmp = dnf_sack_evr_cmp(sack, first->getStreamCStr(), second->getStreamCStr());
+ if (cmp != 0)
+ return cmp < 0;
+ cmp = g_strcmp0(first->getArchCStr(), second->getArchCStr());
+ if (cmp != 0)
+ return cmp < 0;
+ return first->getVersionNum() > second->getVersionNum();
+}
+
+std::vector<std::vector<std::vector<ModulePackage *>>>
+ModulePackageContainer::getLatestModulesPerRepo(ModuleState moduleFilter,
+ std::vector<ModulePackage *> modulePackages)
+{
+ pImpl->addVersion2Modules();
+ if (modulePackages.empty()) {
+ return {};
+ }
+ if (moduleFilter == ModuleState::ENABLED) {
+ std::vector<ModulePackage *> enabled;
+ for (auto package: modulePackages) {
+ if (isEnabled(package)) {
+ enabled.push_back(package);
+ }
+ }
+ modulePackages = enabled;
+ } else if (moduleFilter == ModuleState::DISABLED) {
+ std::vector<ModulePackage *> disabled;
+ for (auto package: modulePackages) {
+ if (isDisabled(package)) {
+ disabled.push_back(package);
+ }
+ }
+ modulePackages = disabled;
+ } else if (moduleFilter == ModuleState::INSTALLED) {
+ std::vector<ModulePackage *> installed;
+ for (auto package: modulePackages) {
+ if ((!getInstalledProfiles(package->getName()).empty()) && isEnabled(package)) {
+ installed.push_back(package);
+ }
+ }
+ modulePackages = installed;
+ }
+ if (modulePackages.empty()) {
+ return {};
+ }
+
+ std::vector<std::vector<std::vector<ModulePackage *>>> output;
+ auto sack = pImpl->moduleSack;
+ std::sort(modulePackages.begin(), modulePackages.end(),
+ [sack](const ModulePackage * first, const ModulePackage * second)
+ {return modulePackageLatestPerRepoSorter(sack, first, second);});
+ auto vectorSize = modulePackages.size();
+
+ auto & packageFirst = modulePackages[0];
+ output.push_back(
+ std::vector<std::vector<ModulePackage *>>{std::vector<ModulePackage *> {packageFirst}});
+ int repoIndex = 0;
+ int nameStreamArchIndex = 0;
+ auto repoID = packageFirst->getRepoID();
+ auto name = packageFirst->getNameCStr();
+ auto stream = packageFirst->getStreamCStr();
+ auto arch = packageFirst->getArchCStr();
+ auto version = packageFirst->getVersionNum();
+
+ for (unsigned int index = 1; index < vectorSize; ++index) {
+ auto & package = modulePackages[index];
+ if (repoID != package->getRepoID()) {
+ repoID = package->getRepoID();
+ name = package->getNameCStr();
+ stream = package->getStreamCStr();
+ arch = package->getArchCStr();
+ version = package->getVersionNum();
+ output.push_back(std::vector<std::vector<ModulePackage *>>{std::vector<ModulePackage *> {package}});
+ ++repoIndex;
+ nameStreamArchIndex = 0;
+ continue;
+ }
+ if (g_strcmp0(package->getNameCStr(), name) != 0 ||
+ g_strcmp0(package->getStreamCStr(), stream) != 0 ||
+ g_strcmp0(package->getArchCStr(), arch) != 0) {
+ name = package->getNameCStr();
+ stream = package->getStreamCStr();
+ arch = package->getArchCStr();
+ version = package->getVersionNum();
+ output[repoIndex].push_back(std::vector<ModulePackage *> {package});
+ ++nameStreamArchIndex;
+ continue;
+ }
+ if (version == package->getVersionNum()) {
+ output[repoIndex][nameStreamArchIndex].push_back(package);
+ }
+ }
+ return output;
+}
+
+std::vector<ModulePackage *>
+ModulePackageContainer::getLatestModules(const std::vector<ModulePackage *> modulePackages, bool activeOnly)
+{
+ // Because modular sovables uses as name combination of module $name:$stream:$context, we can use to get the lates
+ // Query
+ std::vector<ModulePackage *> latestModules;
+ Query query(pImpl->moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ if (activeOnly) {
+ // When no active module return
+ if (!pImpl->activatedModules) {
+ return latestModules;
+ }
+ query.addFilter(HY_PKG, HY_EQ, pImpl->activatedModules.get());
+ }
+
+ PackageSet inputModulePackages(pImpl->moduleSack);
+ for (auto modulePackage : modulePackages) {
+ inputModulePackages.set(modulePackage->getId());
+ }
+ query.addFilter(HY_PKG, HY_EQ, &inputModulePackages);
+ query.addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, 1);
+ auto set = query.runSet();
+
+ Id moduleId = -1;
+ while ((moduleId = set->next(moduleId)) != -1) {
+ latestModules.push_back(pImpl->modules.at(moduleId).get());
+ }
+ return latestModules;
+}
+
+std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType>
+ModulePackageContainer::resolveActiveModulePackages(bool debugSolver)
+{
+ pImpl->addVersion2Modules();
+ dnf_sack_reset_excludes(pImpl->moduleSack);
+ std::vector<ModulePackage *> packages;
+
+ PackageSet excludes(pImpl->moduleSack);
+ // Use only Enabled or Default modules for transaction
+ for (const auto &iter : pImpl->modules) {
+ auto module = iter.second.get();
+ auto moduleState = pImpl->persistor->getState(module->getName());
+ if (moduleState == ModuleState::DISABLED) {
+ excludes.set(module->getId());
+ continue;
+ }
+
+ bool hasDefaultStream;
+ hasDefaultStream = getDefaultStream(module->getName()) == module->getStream();
+ if (isDisabled(module)) {
+ // skip disabled modules
+ continue;
+ } else if (isEnabled(module)) {
+ packages.push_back(module);
+ } else if (hasDefaultStream) {
+ if (moduleState != ModuleState::ENABLED) {
+ pImpl->persistor->changeState(module->getName(), ModuleState::DEFAULT);
+ packages.push_back(module);
+ }
+ }
+ }
+ dnf_sack_add_excludes(pImpl->moduleSack, &excludes);
+ auto problems = pImpl->moduleSolve(packages, debugSolver);
+ return problems;
+}
+
+bool ModulePackageContainer::isModuleActive(Id id)
+{
+ if (pImpl->activatedModules) {
+ return pImpl->activatedModules->has(id);
+ }
+ return false;
+}
+
+bool ModulePackageContainer::isModuleActive(const ModulePackage * modulePackage)
+{
+ if (pImpl->activatedModules) {
+ return pImpl->activatedModules->has(modulePackage->getId());
+ }
+ return false;
+}
+
+std::vector<ModulePackage *> ModulePackageContainer::getModulePackages()
+{
+ pImpl->addVersion2Modules();
+ std::vector<ModulePackage *> values;
+ const auto & modules = pImpl->modules;
+ std::transform(
+ std::begin(modules), std::end(modules), std::back_inserter(values),
+ [](const std::map<Id, std::unique_ptr<ModulePackage>>::value_type & pair){ return pair.second.get(); });
+
+ return values;
+}
+
+void ModulePackageContainer::save()
+{
+ pImpl->persistor->save(pImpl->installRoot, "/etc/dnf/modules.d");
+}
+
+void ModulePackageContainer::rollback()
+{
+ pImpl->persistor->rollback();
+}
+
+std::map<std::string, std::string> ModulePackageContainer::getEnabledStreams()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getEnabledStreams();
+}
+
+std::vector<std::string> ModulePackageContainer::getDisabledModules()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getDisabledModules();
+}
+
+std::map<std::string, std::string> ModulePackageContainer::getDisabledStreams()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getDisabledStreams();
+}
+
+std::vector<std::string> ModulePackageContainer::getResetModules()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getResetModules();
+}
+
+std::map<std::string, std::string> ModulePackageContainer::getResetStreams()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getResetStreams();
+}
+
+std::map<std::string, std::pair<std::string, std::string>>
+ModulePackageContainer::getSwitchedStreams()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getSwitchedStreams();
+}
+
+std::map<std::string, std::vector<std::string>> ModulePackageContainer::getInstalledProfiles()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getInstalledProfiles();
+}
+
+std::vector<std::string> ModulePackageContainer::getInstalledProfiles(std::string moduleName)
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getProfiles(moduleName);
+}
+
+std::map<std::string, std::vector<std::string>> ModulePackageContainer::getRemovedProfiles()
+{
+ pImpl->addVersion2Modules();
+ return pImpl->persistor->getRemovedProfiles();
+}
+const std::string &
+ModulePackageContainer::Impl::ModulePersistor::getStream(const std::string & name)
+{
+ return getEntry(name).second.stream;
+}
+
+inline std::pair<ConfigParser, struct ModulePackageContainer::Impl::ModulePersistor::Config> &
+ModulePackageContainer::Impl::ModulePersistor::getEntry(const std::string & moduleName)
+{
+ try {
+ auto & entry = configs.at(moduleName);
+ return entry;
+ } catch (std::out_of_range &) {
+ throw NoModuleException(moduleName);
+ }
+}
+
+std::vector<std::string> ModulePackageContainer::Impl::ModulePersistor::getAllModuleNames()
+{
+ std::vector<std::string> output;
+ output.reserve(configs.size());
+ for (auto & item: configs) {
+ output.push_back(item.first);
+ }
+ return output;
+}
+
+bool
+ModulePackageContainer::Impl::ModulePersistor::changeStream(const std::string &name,
+ const std::string &stream)
+{
+ const auto &updatedValue = configs.at(name).second.stream;
+ if (updatedValue == stream)
+ return false;
+ const auto &originValue = configs.at(name).first.getValue(name, "stream");
+ if (originValue != updatedValue && configs.at(name).second.streamChangesNum > 1) {
+ throw EnableMultipleStreamsException(name);
+ }
+ getEntry(name).second.stream = stream;
+ return true;
+}
+
+const std::vector<std::string> &
+ModulePackageContainer::Impl::ModulePersistor::getProfiles(const std::string &name)
+{
+ return getEntry(name).second.profiles;
+}
+
+bool ModulePackageContainer::Impl::ModulePersistor::addProfile(
+ const std::string &name, const std::string &profile)
+{
+ auto & profiles = getEntry(name).second.profiles;
+ const auto &it = std::find(std::begin(profiles), std::end(profiles), profile);
+ if (it != std::end(profiles))
+ return false;
+
+ profiles.push_back(profile);
+ return true;
+}
+
+bool ModulePackageContainer::Impl::ModulePersistor::removeProfile(
+ const std::string &name, const std::string &profile)
+{
+ auto &profiles = getEntry(name).second.profiles;
+
+ for (auto it = profiles.begin(); it != profiles.end(); it++) {
+ if (*it == profile) {
+ profiles.erase(it);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const ModulePackageContainer::ModuleState &
+ModulePackageContainer::Impl::ModulePersistor::getState(const std::string &name)
+{
+ return getEntry(name).second.state;
+}
+
+bool ModulePackageContainer::Impl::ModulePersistor::changeState(
+ const std::string &name, ModuleState state)
+{
+ if (getEntry(name).second.state == state)
+ return false;
+
+ getEntry(name).second.state = state;
+ return true;
+}
+
+static inline void
+initConfig(ConfigParser & parser, const std::string & name)
+{
+ parser.addSection(name);
+ parser.setValue(name, "name", name);
+ parser.setValue(name, "stream", EMPTY_STREAM);
+ parser.setValue(name, "profiles", EMPTY_PROFILES);
+ parser.setValue(name, "state", DEFAULT_STATE);
+}
+
+static inline void
+parseConfig(ConfigParser &parser, const std::string &name, const char *path)
+{
+ auto logger(Log::getLogger());
+
+ try {
+ const auto fname = name + ".module";
+ g_autofree gchar * cfn = g_build_filename(path, fname.c_str(), NULL);
+ parser.read(cfn);
+
+ /* FIXME: init empty config or throw error? */
+ if (!parser.hasOption(name, "stream") || /* stream = <stream_name> */
+ !parser.hasOption(name, "profiles") || /* profiles = <list of profiles> */
+ (!parser.hasOption(name, "state") && !parser.hasOption(name, "enabled"))) {
+ logger->debug("Invalid config file for " + name);
+ initConfig(parser, name);
+ return;
+ }
+
+ /* Old config files might not have an option 'name' */
+ parser.setValue(name, "name", name);
+
+ /* Replace old 'enabled' format by 'state' */
+ if (parser.hasOption(name, "enabled")) {
+ parser.setValue(name, "state", parser.getValue(name, "enabled"));
+ parser.removeOption(name, "enabled");
+ }
+ } catch (const ConfigParser::CantOpenFile &) {
+ /* No module config file present. Fill values in */
+ initConfig(parser, name);
+ return;
+ }
+}
+
+bool ModulePackageContainer::Impl::ModulePersistor::insert(
+ const std::string &moduleName, const char *path)
+{
+ /* There can only be one config file per module */
+ if (configs.find(moduleName) != configs.end()) {
+ return false;
+ }
+
+ auto newEntry = configs.emplace(moduleName, std::make_pair(ConfigParser{}, Config()));
+ auto & parser = newEntry.first->second.first;
+ auto & newConfig = newEntry.first->second.second;
+
+ parseConfig(parser, moduleName, path);
+
+ OptionStringList slist{std::vector<std::string>()};
+ const auto &plist = parser.getValue(moduleName, "profiles");
+ newConfig.profiles = std::move(slist.fromString(plist));
+
+ newConfig.state = fromString(parser.getValue(moduleName, "state"));
+ newConfig.stream = parser.getValue(moduleName, "stream");
+ newConfig.streamChangesNum = 0;
+
+ return true;
+}
+
+bool ModulePackageContainer::Impl::ModulePersistor::update(const std::string & name)
+{
+ bool changed = false;
+ auto & parser = getEntry(name).first;
+
+ const auto & state = toString(getState(name));
+ if (!parser.hasOption(name, "state") || parser.getValue(name, "state") != state) {
+ parser.setValue(name, "state", state);
+ changed = true;
+ }
+
+ const auto & stream = getStream(name);
+ if (!parser.hasOption(name, "stream") || parser.getValue(name, "stream") != stream) {
+ parser.setValue(name, "stream", stream);
+ changed = true;
+ }
+
+ OptionStringList profiles{getProfiles(name)};
+ if (!parser.hasOption(name, "profiles") ||
+ OptionStringList(parser.getValue(name, "profiles")).getValue() != profiles.getValue()) {
+ parser.setValue(name, "profiles", profiles.getValueString());
+ changed = true;
+ }
+
+ return changed;
+}
+
+void ModulePackageContainer::Impl::ModulePersistor::reset(const std::string & name)
+{
+ auto & entry = getEntry(name);
+ auto & parser = entry.first;
+
+ entry.second.stream = parser.getValue(name, "stream");
+ entry.second.state = fromString(parser.getValue(name, "state"));
+ OptionStringList slist{std::vector<std::string>()};
+ entry.second.profiles = slist.fromString(parser.getValue(name, "profiles"));
+}
+
+void ModulePackageContainer::Impl::ModulePersistor::save(
+ const std::string &installRoot, const std::string &modulesPath)
+{
+ g_autofree gchar * dirname = g_build_filename(
+ installRoot.c_str(), modulesPath.c_str(), "/", NULL);
+ makeDirPath(std::string(dirname));
+
+ for (auto &iter : configs) {
+ const auto &name = iter.first;
+
+ if (update(name)) {
+ g_autofree gchar * fname = g_build_filename(installRoot.c_str(),
+ modulesPath.c_str(), (name + ".module").c_str(), NULL);
+ iter.second.first.write(std::string(fname), false);
+ }
+ }
+}
+
+void ModulePackageContainer::Impl::ModulePersistor::rollback(void)
+{
+ for (auto &iter : configs) {
+ const auto &name = iter.first;
+ reset(name);
+ }
+}
+
+std::map<std::string, std::string>
+ModulePackageContainer::Impl::ModulePersistor::getEnabledStreams()
+{
+ std::map<std::string, std::string> enabled;
+
+ for (const auto &it : configs) {
+ const auto &name = it.first;
+ const auto &newVal = it.second.second.state;
+ const auto &oldVal = fromString(it.second.first.getValue(name, "state"));
+
+ if (oldVal != ModuleState::ENABLED && newVal == ModuleState::ENABLED) {
+ enabled.emplace(name, it.second.second.stream);
+ }
+ }
+
+ return enabled;
+}
+
+std::vector<std::string>
+ModulePackageContainer::Impl::ModulePersistor::getDisabledModules()
+{
+ std::vector<std::string> disabled;
+
+ for (const auto & it : configs) {
+ const auto & name = it.first;
+ const auto & newVal = it.second.second.state;
+ const auto & oldVal = fromString(it.second.first.getValue(name, "state"));
+ if (oldVal != ModuleState::DISABLED && newVal == ModuleState::DISABLED) {
+ disabled.emplace_back(name);
+ }
+ }
+
+ return disabled;
+}
+
+std::map<std::string, std::string>
+ModulePackageContainer::Impl::ModulePersistor::getDisabledStreams()
+{
+ std::map<std::string, std::string> disabled;
+
+ for (const auto &it : configs) {
+ const auto &name = it.first;
+ const auto &newVal = it.second.second.state;
+ const auto &oldVal = fromString(it.second.first.getValue(name, "state"));
+ if (oldVal != ModuleState::DISABLED && newVal == ModuleState::DISABLED) {
+ disabled.emplace(name, it.second.first.getValue(name, "stream"));
+ }
+ }
+
+ return disabled;
+}
+
+
+std::vector<std::string>
+ModulePackageContainer::Impl::ModulePersistor::getResetModules()
+{
+ std::vector<std::string> result;
+
+ for (const auto & it : configs) {
+ const auto & name = it.first;
+ const auto & newVal = it.second.second.state;
+ const auto & oldVal = fromString(it.second.first.getValue(name, "state"));
+ // when resetting module state, UNKNOWN and DEFAULT are treated equally,
+ // because they are both represented as 'state=' in the config file
+ // and the only difference is internal state based on module defaults
+ if (oldVal == ModuleState::UNKNOWN || oldVal == ModuleState::DEFAULT) {
+ continue;
+ }
+ if (newVal == ModuleState::UNKNOWN || newVal == ModuleState::DEFAULT) {
+ result.emplace_back(name);
+ }
+ }
+
+ return result;
+}
+
+std::map<std::string, std::string>
+ModulePackageContainer::Impl::ModulePersistor::getResetStreams()
+{
+ std::map<std::string, std::string> result;
+
+ for (const auto &it : configs) {
+ const auto &name = it.first;
+ const auto &newVal = it.second.second.state;
+ const auto &oldVal = fromString(it.second.first.getValue(name, "state"));
+ // when resetting module state, UNKNOWN and DEFAULT are treated equally,
+ // because they are both represented as 'state=' in the config file
+ // and the only difference is internal state based on module defaults
+ if (oldVal == ModuleState::UNKNOWN || oldVal == ModuleState::DEFAULT) {
+ continue;
+ }
+ if (newVal == ModuleState::UNKNOWN || newVal == ModuleState::DEFAULT) {
+ result.emplace(name, it.second.first.getValue(name, "stream"));
+ }
+ }
+
+ return result;
+}
+
+std::map<std::string, std::pair<std::string, std::string>>
+ModulePackageContainer::Impl::ModulePersistor::getSwitchedStreams()
+{
+ std::map<std::string, std::pair<std::string, std::string>> switched;
+
+ for (const auto &it : configs) {
+ const auto &name = it.first;
+ const auto &oldVal = it.second.first.getValue(name, "stream");
+ const auto &newVal = it.second.second.stream;
+ // Do not report enabled stream as switched
+ if (oldVal.empty()) {
+ continue;
+ }
+ // Do not report disabled stream as switched
+ if (newVal.empty()) {
+ continue;
+ }
+ if (oldVal != newVal) {
+ switched.emplace(name, std::make_pair(oldVal, newVal));
+ }
+ }
+
+ return switched;
+}
+
+std::map<std::string, std::vector<std::string>>
+ModulePackageContainer::Impl::ModulePersistor::getInstalledProfiles()
+{
+ std::map<std::string, std::vector<std::string>> profiles;
+ for (auto & it : configs) {
+ OptionStringList slist{std::vector<std::string>()};
+ const auto & name = it.first;
+ const auto & parser = it.second.first;
+ auto & newProfiles = it.second.second.profiles;
+
+ auto vprof = slist.fromString(parser.getValue(name, "profiles"));
+ std::sort(vprof.begin(), vprof.end());
+ std::sort(newProfiles.begin(), newProfiles.end());
+ std::vector<std::string> profDiff;
+ std::set_difference(newProfiles.begin(), newProfiles.end(),
+ vprof.begin(), vprof.end(),
+ std::back_inserter(profDiff));
+
+ if (profDiff.size() > 0) {
+ profiles.emplace(name, std::move(profDiff));
+ }
+ }
+
+ return profiles;
+}
+
+std::map<std::string, std::vector<std::string>>
+ModulePackageContainer::Impl::ModulePersistor::getRemovedProfiles()
+{
+ std::map<std::string, std::vector<std::string>> profiles;
+
+ for (auto & it : configs) {
+ OptionStringList slist{std::vector<std::string>()};
+ const auto & name = it.first;
+ const auto & parser = it.second.first;
+ auto & newProfiles = it.second.second.profiles;
+
+ auto vprof = slist.fromString(parser.getValue(name, "profiles"));
+ std::sort(vprof.begin(), vprof.end());
+ std::sort(newProfiles.begin(), newProfiles.end());
+ std::vector<std::string> profDiff;
+ std::set_difference(vprof.begin(), vprof.end(),
+ newProfiles.begin(), newProfiles.end(),
+ std::back_inserter(profDiff));
+ if (profDiff.size() > 0) {
+ profiles.emplace(name, std::move(profDiff));
+ }
+ }
+
+ return profiles;
+}
+
+void ModulePackageContainer::loadFailSafeData()
+{
+ pImpl->addVersion2Modules();
+ auto persistor = pImpl->persistor->configs;
+
+ std::map<std::string, std::pair<std::string, bool>> enabledStreams;
+ for (auto & nameConfig: persistor) {
+ if (nameConfig.second.second.state == ModuleState::ENABLED) {
+ auto & stream = nameConfig.second.second.stream;
+ if (!stream.empty()) {
+ enabledStreams.emplace(nameConfig.first, std::make_pair(stream, false));
+ }
+ }
+ }
+ for (auto & modulePair: pImpl->modules) {
+ auto module = modulePair.second.get();
+ auto it = enabledStreams.find(module->getName());
+ if (it != enabledStreams.end() && it->second.first == module->getStream()) {
+ it->second.second = true;
+ }
+ }
+ auto fileNames = getYamlFilenames(pImpl->persistDir.c_str());
+ auto begin = fileNames.begin();
+ auto end = fileNames.end();
+ for (auto & pair: enabledStreams) {
+ if (!pair.second.second) {
+ // load from disk
+ std::ostringstream ss;
+ ss << pair.first << ":" << pair.second.first << ":";
+ bool loaded = false;
+ auto searchPrefix = ss.str();
+ auto low = std::lower_bound(begin, end, searchPrefix, stringStartWithLowerComparator);
+ for (; low != end && string::startsWith((*low), searchPrefix); ++low) {
+ g_autofree gchar * file = g_build_filename(
+ pImpl->persistDir.c_str(), low->c_str(), NULL);
+ try {
+ auto yamlContent = getFileContent(file);
+ add(yamlContent, LIBDNF_MODULE_FAIL_SAFE_REPO_NAME);
+ loaded = true;
+ } catch (const std::exception &) {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(
+ _("Unable to load modular Fail-Safe data at '%s'"), file));
+ }
+ }
+ if (!loaded) {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(
+ _("Unable to load modular Fail-Safe data for module '%s:%s'"),
+ pair.first, pair.second.first));
+ }
+ }
+ }
+}
+
+std::vector<ModulePackage *> ModulePackageContainer::Impl::getLatestActiveEnabledModules()
+{
+ Query query(moduleSack, Query::ExcludeFlags::IGNORE_EXCLUDES);
+ query.addFilter(HY_PKG, HY_EQ, activatedModules.get());
+ query.addFilter(HY_PKG_REPONAME, HY_NEQ, HY_SYSTEM_REPO_NAME);
+ query.addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, 1);
+ auto set = query.runSet();
+
+ std::vector<ModulePackage *> activeModules;
+ Id moduleId = -1;
+ while ((moduleId = set->next(moduleId)) != -1) {
+ auto modulePackage = modules.at(moduleId).get();
+ if (isEnabled(modulePackage->getName(), modulePackage->getStream())) {
+ activeModules.push_back(modulePackage);
+ }
+ }
+ return activeModules;
+}
+
+void ModulePackageContainer::Impl::addVersion2Modules()
+{
+ if (modulesV2.empty()) {
+ return;
+ }
+ std::map<std::string, std::map<std::string, std::vector<ModulePackage *>>> v3_context_map;
+ for (auto const & module_pair : modules) {
+ auto * module = module_pair.second.get();
+ auto dep_requires = module->getRequires(true);
+ auto concentratedRequires = concentrateVectorString(dep_requires);
+ v3_context_map[module->getNameStream()][concentratedRequires].push_back(module);
+ }
+ libdnf::LibsolvRepo * repo;
+ ModulemdModuleStream * mdStream;
+ std::string repoID;
+ g_autofree gchar * path = g_build_filename(installRoot.c_str(), "/etc/dnf/modules.d", NULL);
+ for (auto & module_tuple : modulesV2) {
+ std::tie(repo, mdStream, repoID) = module_tuple;
+ auto nameStream = ModulePackage::getNameStream(mdStream);
+ auto dep_requires = ModulePackage::getRequires(mdStream, true);
+ auto concentratedRequires = concentrateVectorString(dep_requires);
+ auto streamIterator = v3_context_map.find(nameStream);
+ if (streamIterator != v3_context_map.end()) {
+ auto contextIterator = streamIterator->second.find(concentratedRequires);
+ if (contextIterator != streamIterator->second.end()) {
+ auto v3_context = contextIterator->second[0]->getContext();
+ std::unique_ptr<ModulePackage> modulePackage(new ModulePackage(moduleSack, repo, mdStream, repoID, v3_context));
+ persistor->insert(modulePackage->getName(), path);
+ modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage)));
+ g_object_unref(mdStream);
+ continue;
+ }
+ }
+ if (concentratedRequires.empty()) {
+ concentratedRequires.append("NoRequires");
+ }
+ std::unique_ptr<ModulePackage> modulePackage(new ModulePackage(moduleSack, repo, mdStream, repoID, concentratedRequires));
+ persistor->insert(modulePackage->getName(), path);
+ modules.insert(std::make_pair(modulePackage->getId(), std::move(modulePackage)));
+ g_object_unref(mdStream);
+ }
+ modulesV2.clear();
+}
+
+void ModulePackageContainer::updateFailSafeData()
+{
+ auto fileNames = getYamlFilenames(pImpl->persistDir.c_str());
+
+ if (pImpl->activatedModules) {
+ std::vector<ModulePackage *> latest = pImpl->getLatestActiveEnabledModules();
+
+ if (g_mkdir_with_parents(pImpl->persistDir.c_str(), 0755) == -1) {
+ const char * errTxt = strerror(errno);
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(
+ _("Unable to create directory \"%s\" for modular Fail Safe data: %s"),
+ pImpl->persistDir.c_str(), errTxt));
+ }
+
+ // Update FailSafe data
+ for (auto modulePackage: latest) {
+ std::ostringstream ss;
+ ss << modulePackage->getNameStream();
+ ss << ":" << modulePackage->getArch() << ".yaml";
+ auto fileName = ss.str();
+ if (modulePackage->getRepoID() == LIBDNF_MODULE_FAIL_SAFE_REPO_NAME) {
+ continue;
+ }
+ g_autofree gchar * filePath = g_build_filename(pImpl->persistDir.c_str(), fileName.c_str(), NULL);
+ if (!updateFile(filePath, modulePackage->getYaml().c_str())) {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(_("Unable to save a modular Fail Safe data to '%s'"), filePath));
+ }
+ }
+ }
+
+ // Remove files from not enabled modules
+ for (unsigned int index = 0; index < fileNames.size(); ++index) {
+ auto fileName = fileNames[index];
+ auto first = fileName.find(":");
+ if (first == std::string::npos || first == 0) {
+ continue;
+ }
+ std::string moduleName = fileName.substr(0, first);
+ auto second = fileName.find(":", ++first);
+ if (second == std::string::npos || first == second) {
+ continue;
+ }
+ std::string moduleStream = fileName.substr(first, second - first);
+
+ if (!isEnabled(moduleName, moduleStream)) {
+ g_autofree gchar * file = g_build_filename(pImpl->persistDir.c_str(), fileNames[index].c_str(), NULL);
+ if (remove(file)) {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(_("Unable to remove a modular Fail Safe data in '%s'"), file));
+ }
+ }
+ }
+}
+
+void ModulePackageContainer::applyObsoletes(){
+ for (const auto &iter : pImpl->modules) {
+ auto modulePkg = iter.second.get();
+ if (!isEnabled(modulePkg)) {
+ continue;
+ }
+ /* We cannot access the eol through the ModulemdModuleStream which is
+ * wrapped in modulePkg because it was created with metedata from only
+ * one repository but other repositories can have new eols which affect
+ * this module stream. We have to use merged modular metadata from all
+ * available repositories.
+ */
+ ModulemdObsoletes *modulePkgObsoletes = pImpl->moduleMetadata.getNewestActiveObsolete(modulePkg);
+ if (modulePkgObsoletes) {
+ auto moduleName = modulemd_obsoletes_get_obsoleted_by_module_name(modulePkgObsoletes);
+ auto moduleStream = modulemd_obsoletes_get_obsoleted_by_module_stream(modulePkgObsoletes);
+
+ if (moduleName && moduleStream) {
+ if (!isDisabled(moduleName)) {
+ enable(moduleName, moduleStream, false);
+ if (std::string(moduleName) != modulePkg->getName()) {
+ reset(modulePkg, false);
+ }
+ } else {
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(
+ _("Unable to apply modular obsoletes to '%s:%s' because target module '%s' is disabled"),
+ modulePkg->getName(), modulePkg->getStream(), moduleName));
+ }
+ } else {
+ reset(modulePkg, false);
+ }
+ }
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_MODULEPACKAGECONTAINER_HPP
+#define LIBDNF_MODULEPACKAGECONTAINER_HPP
+
+#include "libdnf/dnf-utils.h"
+#include "ModulePackage.hpp"
+#include "libdnf/nsvcap.hpp"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include <set>
+#include <stdexcept>
+
+namespace libdnf {
+
+struct ModulePackageContainer
+{
+public:
+ enum class ModuleState {
+ UNKNOWN,
+ ENABLED,
+ DISABLED,
+ DEFAULT,
+ INSTALLED
+ };
+
+ enum class ModuleErrorType {
+ NO_ERROR = 0,
+ INFO,
+ /// Error in module defaults detected during resolvement of module dependencies
+ ERROR_IN_DEFAULTS,
+ /// Error detected during resolvement of module dependencies
+ ERROR,
+ /// Error detected during resolvement of module dependencies - Unexpected error!!!
+ CANNOT_RESOLVE_MODULES,
+ CANNOT_RESOLVE_MODULE_SPEC,
+ CANNOT_ENABLE_MULTIPLE_STREAMS,
+ CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
+ /// Problem with latest modules during resolvement of module dependencies
+ ERROR_IN_LATEST
+ };
+
+ struct Exception : public std::runtime_error
+ {
+ explicit Exception(const std::string &what) : runtime_error(what) {}
+ };
+
+ struct NoModuleException : public Exception
+ {
+ explicit NoModuleException(const std::string &moduleName) : Exception("No such module: " + moduleName) {}
+ };
+
+ struct NoStreamException : public Exception
+ {
+ explicit NoStreamException(const std::string &moduleStream) : Exception("No such stream: " + moduleStream) {}
+ };
+
+ struct EnabledStreamException : public Exception
+ {
+ explicit EnabledStreamException(const std::string &moduleName) : Exception("No enabled stream for module: " + moduleName) {}
+ };
+
+ struct EnableMultipleStreamsException : public Exception
+ {
+ explicit EnableMultipleStreamsException(const std::string & moduleName);
+ };
+
+ struct ConflictException : public Exception
+ {
+ explicit ConflictException(const std::string &what) : Exception(what) {}
+ };
+
+ struct ResolveException : public Exception
+ {
+ explicit ResolveException(const std::string &what) : Exception(what) {}
+ };
+
+ explicit ModulePackageContainer(bool allArch, std::string installRoot, const char * arch,
+ const char * persistDir = nullptr);
+ ~ModulePackageContainer();
+
+ void add(const std::string & fileContent, const std::string & repoID);
+
+ /**
+ * @brief Can raise ModulePackageContainer::ConflictException
+ *
+ */
+ void add(DnfSack * sack);
+
+ /**
+ * @brief Can raise ModulePackageContainer::ConflictException
+ *
+ */
+ void addDefaultsFromDisk();
+ void moduleDefaultsResolve();
+ Id addPlatformPackage(const std::string &osReleasePath, const char * platformModule);
+ Id addPlatformPackage(DnfSack * sack,
+ const std::vector<std::string> & osReleasePath, const char * platformModule);
+ /// DEPRECATED
+ void createConflictsBetweenStreams();
+
+ /**
+ * @brief Return true if no module package in container
+ *
+ * @return bool
+ */
+ bool empty() const noexcept;
+
+ /**
+ * @brief Can throw std::out_of_range exception
+ */
+ ModulePackage * getModulePackage(Id id);
+ std::vector<ModulePackage *> getModulePackages();
+ std::vector<std::vector<std::vector<ModulePackage *>>> getLatestModulesPerRepo(
+ ModuleState moduleFilter, std::vector<ModulePackage *> modulePackages);
+
+ /**
+ * @brief Return all latest ModulePackages for each module Name, stream, context and architecture. In case of
+ * multiple latest packages, all will be returned. When activeOnly is true, it returns only the latest active
+ * packages.
+ *
+ * @return std::vector<ModulePackage *>
+ */
+ std::vector<ModulePackage *> getLatestModules(const std::vector<ModulePackage *> modulePackages, bool activeOnly);
+
+ ModulePackage * getLatestModule(std::vector<ModulePackage *> modulePackages, bool activeOnly);
+
+ std::vector<ModulePackage *> requiresModuleEnablement(const libdnf::PackageSet & packages);
+
+ /**
+ * @brief Enable module stream. Return true if requested change realy triggers a change in
+ * the persistor.
+ * When the count parameter is set to false the change will not count towards the limit of
+ * module state modifications.
+ * It can throw ModulePackageContainer::EnableMultipleStreamsException or
+ * ModulePackageContainer::NoModuleException exceprion if module do not exist
+ *
+ * @return bool
+ */
+ bool enable(const std::string &name, const std::string &stream, const bool count = true);
+
+ /**
+ * @brief Enable module stream. Return true if requested changes realy triggers a change in
+ * the persistor.
+ * When the count parameter is set to false the change will not count towards the limit of
+ * module state modifications.
+ * It can throw ModulePackageContainer::EnableMultipleStreamsException or
+ * ModulePackageContainer::NoModuleException exceprion if module do not exist
+ *
+ * @return bool
+ */
+ bool enable(const ModulePackage * module, const bool count = true);
+ /**
+ * @brief unmark module 'name' from any streams
+ * When the count parameter is set to false the change will not count towards the limit of
+ * module state modifications.
+ */
+ void disable(const std::string & name, const bool count = true);
+ void disable(const ModulePackage * module, const bool count = true);
+ /**
+ * @brief Reset module state so it's no longer enabled or disabled.
+ * When the count parameter is set to false the change will not count towards the limit of
+ * module state modifications.
+ */
+ void reset(const std::string &name, const bool count = true);
+ void reset(const ModulePackage * module, const bool count = true);
+ /**
+ * @brief add profile to name:stream
+ */
+ void install(const std::string &name, const std::string &stream, const std::string &profile);
+ void install(const ModulePackage * module, const std::string &profile);
+ /**
+ * @brief remove profile from name:stream
+ */
+ void uninstall(const std::string &name, const std::string &stream, const std::string &profile);
+ void uninstall(const ModulePackage * module, const std::string &profile);
+ /**
+ * @brief commit module changes to storage
+ */
+ void save();
+ /**
+ * @brief discard all module changes and revert to storage state
+ */
+ void rollback();
+ /**
+ * @brief Are there any changes to be saved?
+ */
+ bool isChanged();
+
+ bool isEnabled(const std::string &name, const std::string &stream);
+ bool isEnabled(const ModulePackage * module);
+
+ bool isDisabled(const std::string &name);
+ bool isDisabled(const ModulePackage * module);
+ ModuleState getModuleState(const std::string & name);
+ std::set<std::string> getInstalledPkgNames();
+
+ std::string getReport();
+
+ /**
+ * @brief Get configured default profiles for module stream
+ */
+ std::vector<std::string> getDefaultProfiles(std::string moduleName, std::string moduleStream);
+
+ /**
+ * @brief Get configured default stream for a module
+ */
+ const std::string & getDefaultStream(const std::string &name) const;
+
+ /**
+ * @brief get enabled stream for a module
+ */
+ const std::string & getEnabledStream(const std::string &name);
+
+ /**
+ * @brief list of name:stream for module streams that are to be enable
+ */
+ std::map<std::string, std::string> getEnabledStreams();
+
+ /**
+ * @brief list of names of modules that are to be disabled
+ */
+ std::vector<std::string> getDisabledModules();
+
+ /**
+ * @brief list of name:stream for module streams that are to be disabled
+ * "Will be removed after 2019-12-31. Use getDisabledModules() instead."
+ */
+ DEPRECATED("Will be removed after 2019-12-31. Use getDisabledModules() instead.")
+ std::map<std::string, std::string> getDisabledStreams();
+
+ /**
+ * @brief list of names of modules that are to be reset
+ */
+ std::vector<std::string> getResetModules();
+
+ /**
+ * @brief list of name:stream for module streams that are to be reset
+ * "Will be removed after 2019-12-31. Use getResetModules() instead."
+ */
+ DEPRECATED("Will be removed after 2019-12-31. Use getResetModules() instead.")
+ std::map<std::string, std::string> getResetStreams();
+ /**
+ * @brief list of name:<old_stream:new_stream> for modules whose stream has changed
+ */
+ std::map<std::string, std::pair<std::string, std::string>> getSwitchedStreams();
+ /**
+ * @brief list of name:[profiles] for module profiles being added
+ */
+ std::map<std::string, std::vector<std::string>> getInstalledProfiles();
+
+ /**
+ * @brief list of installed profiles for module name
+ */
+ std::vector<std::string> getInstalledProfiles(std::string moduleName);
+ /**
+ * @brief list of name:[profiles] for module profiles being removed
+ */
+ std::map<std::string, std::vector<std::string>> getRemovedProfiles();
+ /**
+ * @brief Query modules according libdnf::Nsvcap. But the search ignores profiles
+ *
+ */
+ std::vector<ModulePackage *> query(libdnf::Nsvcap & moduleNevra);
+ /**
+ * @brief Requiers subject in format <name>, <name>:<stream>, or <name>:<stream>:<contex>
+ *
+ * @param subject p_subject:...
+ * @return std::vector<ModulePackage *>
+ */
+ std::vector<ModulePackage *> query(std::string subject);
+ std::vector<ModulePackage *> query(std::string name, std::string stream,
+ std::string version, std::string context, std::string arch);
+ void enableDependencyTree(std::vector<ModulePackage *> & modulePackages);
+ std::pair<std::vector<std::vector<std::string>>, ModulePackageContainer::ModuleErrorType> resolveActiveModulePackages(bool debugSolver);
+ bool isModuleActive(Id id);
+ bool isModuleActive(const ModulePackage * modulePackage);
+ void loadFailSafeData();
+ void updateFailSafeData();
+ void applyObsoletes();
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif //LIBDNF_MODULEPACKAGECONTAINER_HPP
--- /dev/null
+set(MODULE_SOURCES
+ ${MODULE_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModuleMetadata.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModuleDependencies.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModuleProfile.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/utils/utils.hpp"
+#include "ModuleDependencies.hpp"
+
+namespace libdnf {
+
+ModuleDependencies::ModuleDependencies() : dependencies(nullptr) {}
+
+ModuleDependencies::ModuleDependencies(ModulemdDependencies *dependencies)
+ : dependencies(dependencies)
+{
+ g_object_ref(dependencies);
+}
+
+ModuleDependencies::ModuleDependencies(const ModuleDependencies & d)
+ : dependencies(d.dependencies)
+{
+ if (dependencies != nullptr) {
+ g_object_ref(d.dependencies);
+ }
+}
+
+ModuleDependencies & ModuleDependencies::operator=(const ModuleDependencies & d)
+{
+ if (this != &d) {
+ g_object_unref(dependencies);
+ dependencies = d.dependencies;
+ if (dependencies != nullptr) {
+ g_object_ref(dependencies);
+ }
+ }
+ return *this;
+}
+
+ModuleDependencies::~ModuleDependencies()
+{
+ if (dependencies != nullptr) {
+ g_object_unref(dependencies);
+ }
+}
+
+std::vector<std::map<std::string, std::vector<std::string>>> ModuleDependencies::getRequires() const
+{
+ if (!dependencies) {
+ return {};
+ }
+ std::vector<std::map<std::string, std::vector<std::string>>> resultRequires;
+ // In order to preserve API we return vector of maps but there can ever only be one map
+ resultRequires.reserve(1);
+ std::map<std::string, std::vector<std::string>> moduleRequirements;
+
+ char** runtimeReqModules = modulemd_dependencies_get_runtime_modules_as_strv(dependencies);
+
+ for (char **iterModule = runtimeReqModules; iterModule && *iterModule; iterModule++) {
+ char** runtimeReqStreams = modulemd_dependencies_get_runtime_streams_as_strv(dependencies, *iterModule);
+ std::string moduleName = static_cast<char *>(*iterModule);
+ auto & moduleStreamVector = moduleRequirements[moduleName];
+ for (char **iterStream = runtimeReqStreams; iterStream && *iterStream; iterStream++) {
+ moduleStreamVector.emplace_back(*iterStream);
+ }
+ g_strfreev(runtimeReqStreams);
+ }
+ resultRequires.push_back(moduleRequirements);
+ g_strfreev(runtimeReqModules);
+
+ return resultRequires;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_MODULEDEPENDENCIES_HPP
+#define LIBDNF_MODULEDEPENDENCIES_HPP
+
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <modulemd-2.0/modulemd.h>
+
+namespace libdnf {
+
+class ModuleDependencies
+{
+public:
+ explicit ModuleDependencies();
+ explicit ModuleDependencies(ModulemdDependencies *dependencies);
+ ModuleDependencies(const ModuleDependencies & d);
+ ModuleDependencies & operator=(const ModuleDependencies & d);
+ ~ModuleDependencies();
+
+ std::vector<std::map<std::string, std::vector<std::string> > > getRequires() const;
+
+private:
+ ModulemdDependencies *dependencies;
+};
+
+}
+
+#endif //LIBDNF_MODULEDEPENDENCIES_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ModuleMetadata.hpp"
+
+#include "../ModulePackageContainer.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "../../log.hpp"
+
+namespace libdnf {
+
+ModuleMetadata::ModuleMetadata(): resultingModuleIndex(NULL), moduleMerger(NULL) {}
+
+ModuleMetadata::ModuleMetadata(const ModuleMetadata & m)
+ : resultingModuleIndex(m.resultingModuleIndex), moduleMerger(m.moduleMerger)
+{
+ if (resultingModuleIndex != nullptr) {
+ g_object_ref(resultingModuleIndex);
+ }
+ if (moduleMerger != nullptr) {
+ g_object_ref(moduleMerger);
+ }
+}
+
+ModuleMetadata & ModuleMetadata::operator=(const ModuleMetadata & m)
+{
+ if (this != &m) {
+ if (resultingModuleIndex != nullptr) {
+ g_object_unref(resultingModuleIndex);
+ }
+ if (moduleMerger != nullptr) {
+ g_object_unref(moduleMerger);
+ }
+ resultingModuleIndex = m.resultingModuleIndex;
+ moduleMerger = m.moduleMerger;
+ if (resultingModuleIndex != nullptr) {
+ g_object_ref(resultingModuleIndex);
+ }
+ if (moduleMerger != nullptr) {
+ g_object_ref(moduleMerger);
+ }
+ }
+ return *this;
+}
+
+ModuleMetadata::~ModuleMetadata()
+{
+ if (resultingModuleIndex != nullptr) {
+ g_object_unref(resultingModuleIndex);
+ }
+ if (moduleMerger != nullptr) {
+ g_object_unref(moduleMerger);
+ }
+}
+
+void ModuleMetadata::addMetadataFromString(const std::string & yaml, int priority)
+{
+ GError *error = NULL;
+ g_autoptr(GPtrArray) failures = NULL;
+
+ ModulemdModuleIndex * mi = modulemd_module_index_new();
+ gboolean success = modulemd_module_index_update_from_string(mi, yaml.c_str(), FALSE, &failures, &error);
+ if(!success){
+ ModuleMetadata::reportFailures(failures);
+ }
+ if (error)
+ throw ModulePackageContainer::ResolveException( tfm::format(_("Failed to update from string: %s"), error->message));
+
+ if (!moduleMerger){
+ moduleMerger = modulemd_module_index_merger_new();
+ if (resultingModuleIndex){
+ // Priority is set to 0 in order to use the current resultingModuleIndex data as a baseline
+ modulemd_module_index_merger_associate_index(moduleMerger, resultingModuleIndex, 0);
+ g_clear_pointer(&resultingModuleIndex, g_object_unref);
+ }
+ }
+
+ modulemd_module_index_merger_associate_index(moduleMerger, mi, priority);
+ g_object_unref(mi);
+}
+
+void ModuleMetadata::resolveAddedMetadata()
+{
+ if (!moduleMerger)
+ return;
+
+ GError *error = NULL;
+
+ resultingModuleIndex = modulemd_module_index_merger_resolve(moduleMerger, &error);
+ if (error && !resultingModuleIndex){
+ throw ModulePackageContainer::ResolveException(tfm::format(_("Failed to resolve: %s"),
+ (error->message) ? error->message : "Unknown error"));
+ }
+ if (error) {
+ auto logger(libdnf::Log::getLogger());
+ logger->debug(tfm::format(_("There were errors while resolving modular defaults: %s"), error->message));
+ }
+
+ modulemd_module_index_upgrade_defaults(resultingModuleIndex, MD_DEFAULTS_VERSION_ONE, &error);
+ if (error)
+ throw ModulePackageContainer::ResolveException(tfm::format(_("Failed to upgrade defaults: %s"), error->message));
+ modulemd_module_index_upgrade_streams(resultingModuleIndex, MD_MODULESTREAM_VERSION_TWO, &error);
+ if (error)
+ throw ModulePackageContainer::ResolveException(tfm::format(_("Failed to upgrade streams: %s"), error->message));
+ g_clear_pointer(&moduleMerger, g_object_unref);
+}
+
+std::vector<ModulePackage *> ModuleMetadata::getAllModulePackages(DnfSack * moduleSack,
+ LibsolvRepo * repo,
+ const std::string & repoID,
+ std::vector<std::tuple<LibsolvRepo *, ModulemdModuleStream *, std::string>> & modulesV2)
+{
+ std::vector<ModulePackage *> result;
+ if (!resultingModuleIndex)
+ return result;
+
+ char ** moduleNames = modulemd_module_index_get_module_names_as_strv(resultingModuleIndex);
+
+ for (char **moduleName = moduleNames; moduleName && *moduleName; moduleName++) {
+ ModulemdModule * m = modulemd_module_index_get_module(resultingModuleIndex, *moduleName);
+ GPtrArray * streams = modulemd_module_get_all_streams(m);
+ //TODO(amatej): replace with
+ //GPtrArray * streams = modulemd_module_index_search_streams_by_nsvca_glob(resultingModuleIndex, NULL);
+ for (unsigned int i = 0; i < streams->len; i++){
+ ModulemdModuleStream * moduleMdStream = static_cast<ModulemdModuleStream *>(g_ptr_array_index(streams, i));
+ if (modulemd_module_stream_v2_is_static_context((ModulemdModuleStreamV2 *) moduleMdStream)) {
+ result.push_back(new ModulePackage(moduleSack, repo, moduleMdStream, repoID));
+ } else {
+ g_object_ref(moduleMdStream);
+ modulesV2.push_back(std::make_tuple(repo, moduleMdStream, repoID));
+ }
+ }
+ }
+
+ g_strfreev(moduleNames);
+ return result;
+}
+
+std::map<std::string, std::string> ModuleMetadata::getDefaultStreams()
+{
+ std::map<std::string, std::string> moduleDefaults;
+ if (!resultingModuleIndex)
+ return moduleDefaults;
+
+ GHashTable * table = modulemd_module_index_get_default_streams_as_hash_table(resultingModuleIndex, NULL);
+ GHashTableIter iterator;
+ gpointer key, value;
+ g_hash_table_iter_init(&iterator, table);
+ while (g_hash_table_iter_next(&iterator, &key, &value)) {
+ moduleDefaults[(char *)key] = (char *) value; //defaultStream;
+ }
+
+ g_hash_table_unref(table);
+ return moduleDefaults;
+}
+
+std::vector<std::string> ModuleMetadata::getDefaultProfiles(std::string moduleName, std::string moduleStream)
+{
+ std::vector<std::string> output;
+ if (!resultingModuleIndex)
+ return output;
+
+ ModulemdModule * myModule = modulemd_module_index_get_module(resultingModuleIndex, moduleName.c_str());
+ ModulemdDefaultsV1 * myDefaults = (ModulemdDefaultsV1 *) modulemd_module_get_defaults(myModule);
+ if (!myDefaults)
+ return output;
+
+ char ** list = modulemd_defaults_v1_get_default_profiles_for_stream_as_strv(myDefaults, moduleStream.c_str(), NULL);
+
+ for (char **iter = list; iter && *iter; iter++) {
+ output.emplace_back(*iter);
+ }
+
+ g_strfreev(list);
+ return output;
+}
+
+void ModuleMetadata::reportFailures(const GPtrArray *failures)
+{
+ for (unsigned int i = 0; i < failures->len; i++) {
+ ModulemdSubdocumentInfo * item = (ModulemdSubdocumentInfo *)(g_ptr_array_index(failures, i));
+ std::cerr << "Module yaml error: " << modulemd_subdocument_info_get_gerror(item)->message << "\n";
+ }
+}
+
+ModulemdObsoletes * ModuleMetadata::getNewestActiveObsolete(ModulePackage *modulePkg)
+{
+ ModulemdModule * myModule = modulemd_module_index_get_module(resultingModuleIndex, modulePkg->getNameCStr());
+ if (myModule == nullptr) {
+ return nullptr;
+ }
+
+ GError *error = NULL;
+ ModulemdModuleStream * myStream = modulemd_module_get_stream_by_NSVCA(myModule,
+ modulePkg->getStreamCStr(),
+ modulePkg->getVersionNum(),
+ modulePkg->getContextCStr(),
+ modulePkg->getArchCStr(),
+ &error);
+ if (error) {
+ auto logger(libdnf::Log::getLogger());
+ logger->debug(tfm::format(_("Cannot retrieve module obsoletes because no stream matching %s: %s"),
+ modulePkg->getFullIdentifier(), error->message));
+ return nullptr;
+ }
+
+ if (myStream == nullptr) {
+ return nullptr;
+ }
+
+ return modulemd_module_stream_v2_get_obsoletes_resolved(MODULEMD_MODULE_STREAM_V2(myStream));
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_MODULEMETADATA_HPP
+#define LIBDNF_MODULEMETADATA_HPP
+
+#include <modulemd-2.0/modulemd.h>
+
+#include "../ModulePackage.hpp"
+
+namespace libdnf {
+
+class ModuleMetadata
+{
+public:
+ ModuleMetadata();
+ ModuleMetadata(const ModuleMetadata & m);
+ ModuleMetadata & operator=(const ModuleMetadata & m);
+ ~ModuleMetadata();
+ void addMetadataFromString(const std::string & yaml, int priority);
+ void resolveAddedMetadata();
+ std::vector<ModulePackage *> getAllModulePackages(DnfSack * moduleSack, LibsolvRepo * repo, const std::string & repoID, std::vector<std::tuple<LibsolvRepo *, ModulemdModuleStream *, std::string>> & modulesV2);
+ std::map<std::string, std::string> getDefaultStreams();
+ std::vector<std::string> getDefaultProfiles(std::string moduleName, std::string moduleStream);
+ ModulemdObsoletes * getNewestActiveObsolete(ModulePackage *p);
+
+private:
+ static void reportFailures(const GPtrArray *failures);
+ ModulemdModuleIndex * resultingModuleIndex;
+ ModulemdModuleIndexMerger * moduleMerger;
+};
+
+}
+
+#endif //LIBDNF_MODULEMETADATA_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ModuleProfile.hpp"
+
+namespace libdnf {
+
+ModuleProfile::ModuleProfile(ModulemdProfile *profile)
+ : profile(profile)
+{
+ g_object_ref(profile);
+}
+
+ModuleProfile::ModuleProfile(const ModuleProfile & p)
+ : profile(p.profile)
+{
+ if (profile != nullptr) {
+ g_object_ref(profile);
+ }
+}
+
+ModuleProfile & ModuleProfile::operator=(const ModuleProfile & p)
+{
+ if (this != &p) {
+ g_object_unref(profile);
+ profile = p.profile;
+ if (profile != nullptr) {
+ g_object_ref(profile);
+ }
+ }
+ return *this;
+}
+
+ModuleProfile::~ModuleProfile()
+{
+ if (profile != nullptr) {
+ g_object_unref(profile);
+ }
+}
+
+std::string ModuleProfile::getName() const
+{
+ if (!profile) {
+ return {};
+ }
+ auto name = modulemd_profile_get_name(profile);
+ return name ? name : "";
+}
+
+bool ModuleProfile::isDefault() const
+{
+ if (!profile) {
+ return {};
+ }
+ return modulemd_profile_is_default(profile);
+}
+
+std::string ModuleProfile::getDescription() const
+{
+ if (!profile) {
+ return {};
+ }
+ auto description = modulemd_profile_get_description(profile, NULL);
+ return description ? description : "";
+}
+
+std::vector<std::string> ModuleProfile::getContent() const
+{
+ if (!profile) {
+ return {};
+ }
+ gchar **cRpms = modulemd_profile_get_rpms_as_strv(profile);
+
+ std::vector<std::string> rpms;
+ for (gchar **item = cRpms; *item; ++item) {
+ rpms.emplace_back(*item);
+ g_free(*item);
+ }
+ g_free(cRpms);
+
+ return rpms;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_MODULEPROFILE_HPP
+#define LIBDNF_MODULEPROFILE_HPP
+
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <modulemd-2.0/modulemd.h>
+
+namespace libdnf {
+
+class ModuleProfile
+{
+public:
+ ModuleProfile() : profile(nullptr) {}
+ ModuleProfile(const ModuleProfile & p);
+ ModuleProfile & operator=(const ModuleProfile & p);
+ ~ModuleProfile();
+ std::string getName() const;
+ std::string getDescription() const;
+ std::vector<std::string> getContent() const;
+ bool isDefault() const;
+
+private:
+ friend class ModulePackage;
+ explicit ModuleProfile(ModulemdProfile * profile);
+ ModulemdProfile *profile;
+};
+
+}
+
+#endif //LIBDNF_MODULEPROFILE_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "nevra.hpp"
+#include "hy-nevra.h"
+#include "dnf-sack.h"
+
+#include "regex/regex.hpp"
+
+namespace libdnf {
+
+#define PKG_NAME "([^:(/=<> ]+)"
+#define PKG_EPOCH "(([0-9]+):)?"
+#define PKG_VERSION "([^-:(/=<> ]+)"
+#define PKG_RELEASE PKG_VERSION
+#define PKG_ARCH "([^-:.(/=<> ]+)"
+
+static const Regex NEVRA_FORM_REGEX[]{
+ Regex("^" PKG_NAME "-" PKG_EPOCH PKG_VERSION "-" PKG_RELEASE "\\." PKG_ARCH "$", REG_EXTENDED),
+ Regex("^" PKG_NAME "-" PKG_EPOCH PKG_VERSION "-" PKG_RELEASE "()" "$", REG_EXTENDED),
+ Regex("^" PKG_NAME "-" PKG_EPOCH PKG_VERSION "()" "()" "$", REG_EXTENDED),
+ Regex("^" PKG_NAME "()()" "()" "()" "\\." PKG_ARCH "$", REG_EXTENDED),
+ Regex("^" PKG_NAME "()()" "()" "()" "()" "$", REG_EXTENDED)
+};
+
+bool Nevra::parse(const char * nevraStr, HyForm form)
+{
+ enum { NAME = 1, EPOCH = 3, VERSION = 4, RELEASE = 5, ARCH = 6, _LAST_ };
+ auto matchResult = NEVRA_FORM_REGEX[form - 1].match(nevraStr, false, _LAST_);
+ if (!matchResult.isMatched() || matchResult.getMatchedLen(NAME) == 0)
+ return false;
+ name = matchResult.getMatchedString(NAME);
+ if (matchResult.getMatchedLen(EPOCH) > 0)
+ epoch = atoi(matchResult.getMatchedString(EPOCH).c_str());
+ else
+ epoch = EPOCH_NOT_SET;
+ version = matchResult.getMatchedString(VERSION);
+ release = matchResult.getMatchedString(RELEASE);
+ arch = matchResult.getMatchedString(ARCH);
+ return true;
+}
+
+void
+Nevra::clear() noexcept
+{
+ name.clear();
+ epoch = EPOCH_NOT_SET;
+ version.clear();
+ release.clear();
+ arch.clear();
+}
+
+std::string
+Nevra::getEvr() const
+{
+ if (epoch == EPOCH_NOT_SET)
+ return version + "-" + release;
+ return std::to_string(epoch) + ":" + version + "-" + release;
+}
+
+bool
+Nevra::hasJustName() const
+{
+ return !name.empty() && epoch == EPOCH_NOT_SET &&
+ version.empty() && release.empty() && arch.empty();
+}
+
+int
+Nevra::compareEvr(const Nevra & nevra2, DnfSack *sack) const
+{
+ return dnf_sack_evr_cmp(sack, getEvr().c_str(), nevra2.getEvr().c_str());
+}
+
+int
+Nevra::compare(const Nevra & nevra2) const
+{
+ auto ret = name.compare(nevra2.name);
+ if (ret != 0)
+ return ret;
+ ret = compareEvr(nevra2, nullptr);
+ if (ret != 0)
+ return ret;
+ return arch.compare(nevra2.arch);
+}
+
+}
+
+void
+hy_nevra_free(HyNevra nevra)
+{
+ delete nevra;
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_NEVRA_HPP
+#define LIBDNF_NEVRA_HPP
+
+#include "dnf-types.h"
+#include "hy-subject.h"
+
+#include <string>
+#include <utility>
+
+namespace libdnf {
+
+struct Nevra {
+public:
+ static constexpr int EPOCH_NOT_SET = -1;
+
+ Nevra();
+
+ bool parse(const char * nevraStr, HyForm form);
+ void clear() noexcept;
+
+ const std::string & getName() const noexcept;
+ int getEpoch() const noexcept;
+ const std::string & getVersion() const noexcept;
+ const std::string & getRelease() const noexcept;
+ const std::string & getArch() const noexcept;
+
+ void setName(const std::string & name);
+ void setEpoch(int epoch);
+ void setVersion(const std::string & version);
+ void setRelease(const std::string & release);
+ void setArch(const std::string & arch);
+
+ void setName(std::string && name);
+ void setVersion(std::string && version);
+ void setRelease(std::string && release);
+ void setArch(std::string && arch);
+
+ std::string getEvr() const;
+ bool hasJustName() const;
+ int compareEvr(const Nevra & nevra2, DnfSack *sack) const;
+ int compare(const Nevra & nevra2) const;
+
+private:
+ std::string name;
+ int epoch;
+ std::string version;
+ std::string release;
+ std::string arch;
+};
+
+inline Nevra::Nevra()
+: epoch(EPOCH_NOT_SET) {}
+
+inline const std::string & Nevra::getName() const noexcept
+{
+ return name;
+}
+
+inline int Nevra::getEpoch() const noexcept
+{
+ return epoch;
+}
+
+inline const std::string & Nevra::getVersion() const noexcept
+{
+ return version;
+}
+
+inline const std::string & Nevra::getRelease() const noexcept
+{
+ return release;
+}
+
+inline const std::string & Nevra::getArch() const noexcept {
+ return arch;
+}
+
+inline void Nevra::setName(const std::string & name)
+{
+ this->name = name;
+}
+
+inline void Nevra::setEpoch(int epoch)
+{
+ this->epoch = epoch;
+}
+
+inline void Nevra::setVersion(const std::string & version)
+{
+ this->version = version;
+}
+
+inline void Nevra::setRelease(const std::string & release)
+{
+ this->release = release;
+}
+
+inline void Nevra::setArch(const std::string & arch)
+{
+ this->arch = arch;
+}
+
+inline void Nevra::setName(std::string && name)
+{
+ this->name = std::move(name);
+}
+
+inline void Nevra::setVersion(std::string && version)
+{
+ this->version = std::move(version);
+}
+
+inline void Nevra::setRelease(std::string && release)
+{
+ this->release = std::move(release);
+}
+
+inline void Nevra::setArch(std::string && arch)
+{
+ this->arch = std::move(arch);
+}
+
+}
+
+#endif // LIBDNF_NEVRA_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define HEXADECIMAL DIGITS "abcdef"
+#define MODULE_SPECIAL "+._-"
+#define GLOB "][*?!"
+
+#include "nsvcap.hpp"
+
+#include "libdnf/utils/utils.hpp"
+
+#include <regex/regex.hpp>
+
+namespace libdnf {
+
+#define MODULE_NAME "([" GLOB ASCII_LETTERS DIGITS MODULE_SPECIAL "]+)"
+#define MODULE_STREAM MODULE_NAME
+#define MODULE_VERSION "([" GLOB DIGITS "-]+)"
+#define MODULE_CONTEXT MODULE_NAME
+#define MODULE_ARCH MODULE_NAME
+#define MODULE_PROFILE MODULE_NAME
+
+static const Regex NSVCAP_FORM_REGEX[]{
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION ":" MODULE_CONTEXT "::?" MODULE_ARCH "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION ":" MODULE_CONTEXT "::?" MODULE_ARCH "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION "()" "::" MODULE_ARCH "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION "()" "::" MODULE_ARCH "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM "()" "()" "::" MODULE_ARCH "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM "()" "()" "::" MODULE_ARCH "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION ":" MODULE_CONTEXT "()" "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION "()" "()" "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION ":" MODULE_CONTEXT "()" "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM ":" MODULE_VERSION "()" "()" "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM "()" "()" "()" "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME ":" MODULE_STREAM "()" "()" "()" "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME "()" "()" "()" "::" MODULE_ARCH "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME "()" "()" "()" "::" MODULE_ARCH "\\/?" "()" "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME "()" "()" "()" "()" "\\/" MODULE_PROFILE "$", REG_EXTENDED),
+ Regex("^" MODULE_NAME "()" "()" "()" "()" "\\/?" "()" "$", REG_EXTENDED)
+};
+
+bool Nsvcap::parse(const char *nsvcapStr, HyModuleForm form)
+{
+ enum { NAME = 1, STREAM = 2, VERSION = 3, CONTEXT = 4, ARCH = 5, PROFILE = 6, _LAST_ };
+ auto matchResult = NSVCAP_FORM_REGEX[form - 1].match(nsvcapStr, false, _LAST_);
+ if (!matchResult.isMatched() || matchResult.getMatchedLen(NAME) == 0)
+ return false;
+ name = matchResult.getMatchedString(NAME);
+ version = matchResult.getMatchedString(VERSION);
+ stream = matchResult.getMatchedString(STREAM);
+ context = matchResult.getMatchedString(CONTEXT);
+ arch = matchResult.getMatchedString(ARCH);
+ profile = matchResult.getMatchedString(PROFILE);
+ return true;
+}
+
+void
+Nsvcap::clear()
+{
+ name.clear();
+ stream.clear();
+ version.clear();
+ context.clear();
+ arch.clear();
+ profile.clear();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_NSVCAP_HPP
+#define LIBDNF_NSVCAP_HPP
+
+#include "hy-subject.h"
+
+#include <string>
+
+namespace libdnf {
+
+struct Nsvcap {
+public:
+ bool parse(const char *nsvcapStr, HyModuleForm form);
+ void clear();
+
+ const std::string & getName() const noexcept;
+ const std::string & getStream() const noexcept;
+ const std::string & getVersion() const noexcept;
+ const std::string & getContext() const noexcept;
+ const std::string & getArch() const noexcept;
+ const std::string & getProfile() const noexcept;
+
+ void setName(const std::string & name);
+ void setStream(const std::string & stream);
+ void setVersion(const std::string & stream);
+ void setContext(const std::string & context);
+ void setArch(const std::string & arch);
+ void setProfile(const std::string & profile);
+
+ void setName(std::string && name);
+ void setStream(std::string && stream);
+ void setVersion(std::string && stream);
+ void setContext(std::string && context);
+ void setArch(std::string && arch);
+ void setProfile(std::string && profile);
+
+private:
+ std::string name;
+ std::string stream;
+ std::string version;
+ std::string context;
+ std::string arch;
+ std::string profile;
+};
+
+inline const std::string & Nsvcap::getName() const noexcept
+{
+ return name;
+}
+
+inline const std::string & Nsvcap::getStream() const noexcept
+{
+ return stream;
+}
+
+inline const std::string & Nsvcap::getVersion() const noexcept
+{
+ return version;
+}
+
+inline const std::string & Nsvcap::getContext() const noexcept
+{
+ return context;
+}
+
+inline const std::string & Nsvcap::getArch() const noexcept
+{
+ return arch;
+}
+
+inline const std::string & Nsvcap::getProfile() const noexcept
+{
+ return profile;
+}
+
+inline void Nsvcap::setName(const std::string & name)
+{
+ this->name = name;
+}
+
+inline void Nsvcap::setStream(const std::string & stream)
+{
+ this->stream = stream;
+}
+
+inline void Nsvcap::setVersion(const std::string & version)
+{
+ this->version = version;
+}
+
+inline void Nsvcap::setContext(const std::string & context)
+{
+ this->context = context;
+}
+
+inline void Nsvcap::setArch(const std::string & arch)
+{
+ this->arch = arch;
+}
+
+inline void Nsvcap::setProfile(const std::string & profile)
+{
+ this->profile = profile;
+}
+
+inline void Nsvcap::setName(std::string && name)
+{
+ this->name = std::move(name);
+}
+
+inline void Nsvcap::setStream(std::string && stream)
+{
+ this->stream = std::move(stream);
+}
+
+inline void Nsvcap::setVersion(std::string && version)
+{
+ this->version = std::move(version);
+}
+
+inline void Nsvcap::setContext(std::string && context)
+{
+ this->context = std::move(context);
+}
+
+inline void Nsvcap::setArch(std::string && arch)
+{
+ this->arch = std::move(arch);
+}
+
+inline void Nsvcap::setProfile(std::string && profile)
+{
+ this->profile = std::move(profile);
+}
+
+}
+
+#endif //LIBDNF_NSVCAP_HPP
--- /dev/null
+set(PLUGIN_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp
+ PARENT_SCOPE
+)
+
+set(PLUGIN_PUBLIC_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/plugin.h
+)
+
+install(FILES ${PLUGIN_PUBLIC_HEADERS} DESTINATION include/libdnf/plugin)
--- /dev/null
+libdnf plugin interface
+=======================
+
+Motivation
+----------
+[DNF](https://github.com/rpm-software-management/dnf) package manager that uses the libdnf library, has plugins support. There are useful DNF plugins and some of them needs to be run during each operation. Of course, DNF plugins are run only if user use DNF. If the user will use another application ([microdnf](https://github.com/rpm-software-management/microdnf), [PackageKit](https://github.com/hughsie/PackageKit), ...) DNF plugins are skipped. This is effort to move plugins into lower level - into libdnf. So the plugins will be running even if another application is used.
+
+The libdnf plugins interface is under development now. We cannot simply copy plugin interface from DNF. DNF is a Python application but libdnf is a C/C++ library. That also means not all DNF plugins can be transferred to libdnf. Moreover there is more ways how application can use the libdnf library. DNF use another way (implements upper logic in python) than microdnf and PackageKit (which use libdnf "context" code). It takes time to unify it. Hooks are inserted in "context" code of libdnf now.
+
+Status of prototype
+-------------------
+* Plugins are .so libraries.
+* Plugins are read from directory (default /usr/lib64/libdnf/plugins), links are supported but .so suffix is requested.
+* Plugins are loaded in alphabetical order (sorted by filename).
+* Initializations and hooks are called in the same order as plugins were loaded.
+* Freeing of plugins is in the reverse order as they were loaded.
+* Plugins have access to libdnf context and can use libdnf public functions to read and modify it.
+* Each plugin must implement 4 functions:
+```
+ const PluginInfo * pluginGetInfo(void);
+ PluginHandle * pluginInitHandle(int version, PluginMode mode, DnfPluginInitData * initData);
+ void pluginFreeHandle(PluginHandle * handle);
+ int pluginHook(PluginHandle * handle, PluginHookId id, DnfPluginHookData * hookData, DnfPluginError * error);
+```
+* There are functions to access DnfPluginInitData and DnfPluginHookData:
+```
+ DnfContext * pluginGetContext(DnfPluginInitData * data);
+ DnfTransaction * hookContextTransactionGetTransaction(DnfPluginHookData * data);
+ HyGoal hookContextTransactionGetGoal(DnfPluginHookData * data);
+ DnfState * hookContextTransactionGetState(DnfPluginHookData * data);
+```
+
+Plugin functions
+----------------
+* `const PluginInfo * pluginGetInfo(void)`
+> Returns information about the plugin.
+
+* `PluginHandle * pluginInitHandle(int version, PluginMode mode, DnfPluginInitData * initData)`
+> Initialization of new plugin instance. Returns handle to it.
+
+* `void pluginFreeHandle(PluginHandle * handle)`
+> Frees plugin instance.
+
+* `int pluginHook(PluginHandle * handle, PluginHookId id, DnfPluginHookData * data, DnfPluginError * error)`
+> Called by hook. Each hook is identified by PluginHookId.
+
+Ideas
+-----
+* Only links to plugins .so files will be in the directory.
+* Plugin can be enabled/disabled by adding/removing the link to it. Link name will start with number which defines order of plugin loading. Eg. there are plugins pluginA, pluginB, pluginC, pluginD and we want to use 3 of them in specific order. So we make appropriate links 05pluginA.so, 10pluginD.so, 15pluginB.so.
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_PLUGIN_PRIVATE_HPP
+#define _LIBDNF_PLUGIN_PRIVATE_HPP
+
+#include "plugin.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace libdnf {
+
+class Library {
+public:
+ Library(const char * path);
+ ~Library();
+ const std::string & getPath() const { return path; }
+protected:
+ std::string path;
+ void * handle;
+};
+
+struct PluginError {
+ int code;
+ char * path;
+ char * message;
+};
+
+struct PluginInitData {
+ PluginInitData(PluginMode mode) : mode(mode) {}
+ PluginMode mode;
+};
+
+struct PluginHookData {
+ PluginHookData(PluginHookId hookId) : hookId(hookId) {}
+ PluginHookId hookId;
+};
+
+class Plugin : public Library {
+public:
+ Plugin(const char * path);
+ Plugin(const Plugin &) = delete;
+ Plugin & operator=(const Plugin &) = delete;
+ decltype(&pluginGetInfo) getInfo;
+ decltype(&pluginInitHandle) initHandle;
+ decltype(&pluginFreeHandle) freeHandle;
+ decltype(&pluginHook) hook;
+};
+
+class Plugins {
+public:
+ void loadPlugin(const std::string & filePath);
+ void loadPlugins(std::string dirPath);
+ bool init(PluginMode mode, PluginInitData * initData);
+ void free();
+ bool hook(PluginHookId id, PluginHookData * hookData, DnfPluginError * error);
+ size_t count() const;
+ const PluginInfo * getPluginInfo(size_t index) const;
+ bool isPluginEnabled(size_t index) const;
+ void enablePlugin(size_t index, bool enabled);
+
+private:
+ struct PluginWithData {
+ std::unique_ptr<Plugin> plugin;
+ bool enabled;
+ PluginHandle * handle;
+ };
+ std::vector<PluginWithData> pluginsWithData;
+};
+
+inline size_t Plugins::count() const
+{
+ return pluginsWithData.size();
+}
+
+inline const PluginInfo * Plugins::getPluginInfo(size_t index) const
+{
+ return pluginsWithData.at(index).plugin->getInfo();
+}
+
+inline bool Plugins::isPluginEnabled(size_t index) const
+{
+ return pluginsWithData.at(index).enabled;
+}
+
+inline void Plugins::enablePlugin(size_t index, bool enabled)
+{
+ pluginsWithData.at(index).enabled = enabled;
+}
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "plugin-private.hpp"
+
+#include "../log.hpp"
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include <utils.hpp>
+
+#include <stdexcept>
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PLUGIN_API_VERSION 1
+
+namespace libdnf {
+
+Library::Library(const char * path)
+: path(path)
+{
+ handle = dlopen(path, RTLD_LAZY);
+ if (!handle) {
+ const char * errMsg = dlerror();
+ throw std::runtime_error(tfm::format(_("Can't load shared library \"%s\": %s"), path, errMsg));
+ }
+}
+
+Library::~Library()
+{
+ dlclose(handle);
+}
+
+Plugin::Plugin(const char * path) : Library(path)
+{
+ getInfo = reinterpret_cast<decltype(&pluginGetInfo)>(dlsym(handle, "pluginGetInfo"));
+ if (!getInfo)
+ {
+ const char * errMsg = dlerror();
+ throw std::runtime_error(tfm::format(_("Can't obtain address of symbol \"%s\": %s"), "pluginGetInfo", errMsg));
+ }
+ initHandle = reinterpret_cast<decltype(&pluginInitHandle)>(dlsym(handle, "pluginInitHandle"));
+ if (!initHandle)
+ {
+ const char * errMsg = dlerror();
+ throw std::runtime_error(tfm::format(_("Can't obtain address of symbol \"%s\": %s"), "pluginInitHandle", errMsg));
+ }
+ freeHandle = reinterpret_cast<decltype(&pluginFreeHandle)>(dlsym(handle, "pluginFreeHandle"));
+ if (!freeHandle)
+ {
+ const char * errMsg = dlerror();
+ throw std::runtime_error(tfm::format(_("Can't obtain address of symbol \"%s\": %s"), "pluginFreeHandle", errMsg));
+ }
+ hook = reinterpret_cast<decltype(&pluginHook)>(dlsym(handle, "pluginHook"));
+ if (!hook)
+ {
+ const char * errMsg = dlerror();
+ throw std::runtime_error(tfm::format(_("Can't obtain address of symbol \"%s\": %s"), "pluginHook", errMsg));
+ }
+}
+
+void Plugins::loadPlugin(const std::string & path)
+{
+ auto logger(Log::getLogger());
+ logger->debug(tfm::format(_("Loading plugin file=\"%s\""), path));
+ pluginsWithData.emplace_back(PluginWithData{std::unique_ptr<Plugin>(new Plugin(path.c_str())), true, nullptr});
+ auto info = pluginsWithData.back().plugin->getInfo();
+ logger->debug(tfm::format(_("Loaded plugin name=\"%s\", version=\"%s\""), info->name, info->version));
+}
+
+void Plugins::loadPlugins(std::string dirPath)
+{
+ auto logger(Log::getLogger());
+ if (dirPath.empty())
+ throw std::runtime_error(_("Plugins::loadPlugins() dirPath cannot be empty"));
+ if (dirPath.back() != '/')
+ dirPath.push_back('/');
+ struct dirent **namelist;
+ auto count = scandir(dirPath.c_str(), &namelist,
+ [](const struct dirent *dent)->int{return string::endsWith(dent->d_name, ".so");},
+ alphasort);
+ if (count == -1) {
+ int errnum = errno;
+ logger->warning(tfm::format(_("Can't read plugin directory \"%s\": %s"), dirPath, strerror(errnum)));
+ return;
+ }
+
+ std::string errorMsgs;
+ for (int idx = 0; idx < count; ++idx) {
+ try {
+ loadPlugin((dirPath + namelist[idx]->d_name).c_str());
+ } catch (const std::exception & ex) {
+ std::string msg = tfm::format(_("Can't load plugin \"%s\": %s"), namelist[idx]->d_name, ex.what());
+ logger->error(msg);
+ errorMsgs += msg + '\n';
+ }
+ ::free(namelist[idx]);
+ }
+ ::free(namelist);
+ if (!errorMsgs.empty())
+ throw std::runtime_error(errorMsgs);
+}
+
+bool Plugins::init(PluginMode mode, PluginInitData * initData)
+{
+ for (auto & pluginWithData : pluginsWithData) {
+ if (!pluginWithData.enabled) {
+ continue;
+ }
+ pluginWithData.handle = pluginWithData.plugin->initHandle(PLUGIN_API_VERSION, mode, initData);
+ if (!pluginWithData.handle) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Plugins::free()
+{
+ for (auto it = pluginsWithData.rbegin(); it != pluginsWithData.rend(); ++it) {
+ if (it->handle) {
+ it->plugin->freeHandle(it->handle);
+ }
+ }
+}
+
+bool Plugins::hook(PluginHookId id, PluginHookData * hookData, DnfPluginError * error)
+{
+ for (auto & pluginWithData : pluginsWithData) {
+ if (!pluginWithData.enabled || !pluginWithData.handle) {
+ continue;
+ }
+ if (!pluginWithData.plugin->hook(pluginWithData.handle, id, hookData, error)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_PLUGIN_H
+#define _LIBDNF_PLUGIN_H
+
+#include "../dnf-types.h"
+#include "../hy-types.h"
+
+typedef struct {
+ const char * name;
+ const char * version;
+} PluginInfo;
+
+typedef enum {
+ PLUGIN_MODE_CONTEXT = 10000
+} PluginMode;
+
+typedef enum {
+ PLUGIN_HOOK_ID_CONTEXT_PRE_CONF = 10000,
+ PLUGIN_HOOK_ID_CONTEXT_CONF,
+ PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION,
+ PLUGIN_HOOK_ID_CONTEXT_TRANSACTION,
+ PLUGIN_HOOK_ID_CONTEXT_PRE_REPOS_RELOAD
+} PluginHookId;
+
+#ifdef __cplusplus
+namespace libdnf {
+ struct PluginError;
+ struct PluginInitData;
+ struct PluginHookData;
+}
+typedef struct libdnf::PluginError DnfPluginError;
+typedef struct libdnf::PluginInitData DnfPluginInitData;
+typedef struct libdnf::PluginHookData DnfPluginHookData;
+#else
+typedef struct PluginError DnfPluginError;
+typedef struct PluginInitData DnfPluginInitData;
+typedef struct PluginHookData DnfPluginHookData;
+#endif
+
+typedef struct _PluginHandle PluginHandle;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Functions to access initData.
+DnfContext * pluginGetContext(DnfPluginInitData * data);
+
+// Functions to access hookData.
+// Usable with PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION and PLUGIN_HOOK_ID_CONTEXT_TRANSACTION,
+DnfTransaction * hookContextTransactionGetTransaction(DnfPluginHookData * data);
+HyGoal hookContextTransactionGetGoal(DnfPluginHookData * data);
+DnfState * hookContextTransactionGetState(DnfPluginHookData * data);
+
+// code below will be implemented in plugins
+struct _PluginHandle;
+
+const PluginInfo * pluginGetInfo(void);
+PluginHandle * pluginInitHandle(int version, PluginMode mode, DnfPluginInitData * initData);
+void pluginFreeHandle(PluginHandle * handle);
+int pluginHook(PluginHandle * handle, PluginHookId id, DnfPluginHookData * data, DnfPluginError * error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+add_subdirectory(solvable)
+
+set(REPO_SOURCES
+ ${REPO_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Crypto.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencySplitter.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Repo.cpp
+ PARENT_SCOPE
+)
+
+set(REPO_HEADERS
+ ${REPO_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Crypto.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Repo.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Crypto.hpp"
+#include "Repo.hpp"
+
+#include "../dnf-utils.h"
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "utils.hpp"
+
+#include <librepo/librepo.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+
+#include <utility>
+
+namespace libdnf {
+
+static void throwException(GError * err)
+{
+ LrException ex(err->code, err->message);
+ g_error_free(err);
+ throw ex;
+}
+
+Key::Key(const void * key, const void * subkey)
+ : id{lr_gpg_subkey_get_id(static_cast<const LrGpgSubkey *>(subkey))},
+ fingerprint{lr_gpg_subkey_get_fingerprint(static_cast<const LrGpgSubkey *>(subkey))},
+ timestamp{lr_gpg_subkey_get_timestamp(static_cast<const LrGpgSubkey *>(subkey))},
+ asciiArmoredKey{lr_gpg_key_get_raw_key(static_cast<const LrGpgKey *>(key))}
+{
+ auto * userid_c = lr_gpg_key_get_userids(static_cast<const LrGpgKey *>(key))[0];
+ userid = userid_c ? userid_c : "";
+}
+
+const std::string & Key::getId() const noexcept
+{
+ return id;
+}
+
+const std::string & Key::getUserId() const noexcept
+{
+ return userid;
+}
+
+const std::string & Key::getFingerprint() const noexcept
+{
+ return fingerprint;
+}
+
+long int Key::getTimestamp() const noexcept
+{
+ return timestamp;
+}
+
+const std::string & Key::getAsciiArmoredKey() const noexcept
+{
+ return asciiArmoredKey;
+}
+
+const std::string & Key::getUrl() const noexcept
+{
+ return url;
+}
+
+void Key::setUrl(std::string url)
+{
+ this->url = std::move(url);
+}
+
+std::vector<Key> Key::keysFromFd(int fileDescriptor)
+{
+ std::vector<Key> keyInfos;
+
+ char tmpdir[] = "/tmp/tmpdir.XXXXXX";
+ if (!mkdtemp(tmpdir)) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"),
+ tmpdir, errTxt));
+ }
+ Finalizer tmpDirRemover([&tmpdir](){
+ dnf_remove_recursive(tmpdir, NULL);
+ });
+
+ GError * err = NULL;
+ if (!lr_gpg_import_key_from_fd(fileDescriptor, tmpdir, &err)) {
+ throwException(err);
+ }
+
+ std::unique_ptr<LrGpgKey, decltype(&lr_gpg_keys_free)> lr_keys{
+ lr_gpg_list_keys(TRUE, tmpdir, &err), &lr_gpg_keys_free};
+ if (err) {
+ throwException(err);
+ }
+
+ for (const auto * lr_key = lr_keys.get(); lr_key; lr_key = lr_gpg_key_get_next(lr_key)) {
+ for (const auto * lr_subkey = lr_gpg_key_get_subkeys(lr_key); lr_subkey;
+ lr_subkey = lr_gpg_subkey_get_next(lr_subkey)) {
+ // get first signing subkey
+ if (lr_gpg_subkey_get_can_sign(lr_subkey)) {
+ keyInfos.emplace_back(Key(lr_key, lr_subkey));
+ break;
+ }
+ }
+ }
+
+ return keyInfos;
+}
+
+void importKeyToPubring(const std::string & asciiArmoredKey, const std::string & pubringDir)
+{
+ GError * err = NULL;
+ if (!lr_gpg_import_key_from_memory(asciiArmoredKey.c_str(), asciiArmoredKey.size(), pubringDir.c_str(), &err)) {
+ throwException(err);
+ }
+}
+
+std::vector<std::string> keyidsFromPubring(const std::string & pubringDir)
+{
+ std::vector<std::string> keyids;
+
+ struct stat sb;
+ if (stat(pubringDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ GError * err = NULL;
+ std::unique_ptr<LrGpgKey, decltype(&lr_gpg_keys_free)> lr_keys{
+ lr_gpg_list_keys(FALSE, pubringDir.c_str(), &err), &lr_gpg_keys_free};
+ if (err) {
+ throwException(err);
+ }
+
+ for (const auto * lr_key = lr_keys.get(); lr_key; lr_key = lr_gpg_key_get_next(lr_key)) {
+ for (const auto * lr_subkey = lr_gpg_key_get_subkeys(lr_key); lr_subkey;
+ lr_subkey = lr_gpg_subkey_get_next(lr_subkey)) {
+ // get first signing subkey
+ if (lr_gpg_subkey_get_can_sign(lr_subkey)) {
+ keyids.emplace_back(lr_gpg_subkey_get_id(lr_subkey));
+ break;
+ }
+ }
+ }
+ }
+
+ return keyids;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_CRYPTO_HPP
+#define _LIBDNF_CRYPTO_HPP
+
+#include <string>
+#include <vector>
+
+namespace libdnf {
+
+/**
+* @class Key
+*
+* @brief The class represents information about an OpenPGP key
+*/
+class Key {
+public:
+ /** Loads keys from a file descriptor. Expects ASCII Armored format. */
+ static std::vector<Key> keysFromFd(int fileDescriptor);
+
+ /** Returns the key ID */
+ const std::string & getId() const noexcept;
+
+ /** Returns the user ID of the key */
+ const std::string & getUserId() const noexcept;
+
+ /** Returns key fingerprint */
+ const std::string & getFingerprint() const noexcept;
+
+ /** Returns the key timestamp */
+ long int getTimestamp() const noexcept;
+
+ /** Returns ASCII Armored OpenPGP key */
+ const std::string & getAsciiArmoredKey() const noexcept;
+
+ /** Returns the key source url */
+ const std::string & getUrl() const noexcept;
+
+ /** Sets the key source url */
+ void setUrl(std::string url);
+
+private:
+ Key(const void * key, const void * subkey);
+
+ std::string id;
+ std::string fingerprint;
+ std::string userid;
+ long int timestamp;
+ std::string asciiArmoredKey;
+ std::string url;
+};
+
+/**
+* @brief Imports ASCII Armored OpenPGP key to pubring
+*
+* @param asciiArmoredKey ASCII Armored OpenPGP key
+* @param pubringDir path to the pubring directory
+*/
+void importKeyToPubring(const std::string & asciiArmoredKey, const std::string & pubringDir);
+
+/**
+* @brief Retrieves the IDs of the keys in the pubring
+*
+* @param pubringDir path to the pubring directory
+*
+* @return List of key IDs in the pubrig
+*/
+std::vector<std::string> keyidsFromPubring(const std::string & pubringDir);
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "DependencySplitter.hpp"
+#include "../dnf-sack.h"
+#include "../log.hpp"
+#include "../utils/regex/regex.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+
+namespace libdnf {
+
+// Avoid using the \s and \S patterns here as they are GNU extensions and aren't portable.
+static const Regex RELDEP_REGEX =
+ Regex("^([^[:space:]]*)[[:space:]]*(<=|>=|<|>|=|==)?[[:space:]]*([^[:space:]]*)$", REG_EXTENDED);
+
+static bool
+getCmpFlags(int *cmp_type, std::string matchCmpType)
+{
+ auto logger(Log::getLogger());
+ int subexpr_len = matchCmpType.size();
+ auto match_start = matchCmpType.c_str();
+ if (subexpr_len == 2) {
+ if (strncmp(match_start, "<=", 2) == 0) {
+ *cmp_type |= HY_LT;
+ *cmp_type |= HY_EQ;
+ }
+ else if (strncmp(match_start, ">=", 2) == 0) {
+ *cmp_type |= HY_GT;
+ *cmp_type |= HY_EQ;
+ }
+ else if (strncmp(match_start, "==", 2) == 0) {
+ auto msg = tfm::format(_("Using '==' operator in reldeps can result in an undefined "
+ "behavior. It is deprecated and the support will be dropped "
+ "in future versions. Use '=' operator instead."));
+ logger->warning(msg);
+ *cmp_type |= HY_EQ;
+ }
+ else
+ return false;
+ } else if (subexpr_len == 1) {
+ if (*match_start == '<')
+ *cmp_type |= HY_LT;
+ else if (*match_start == '>')
+ *cmp_type |= HY_GT;
+ else if (*match_start == '=')
+ *cmp_type |= HY_EQ;
+ else
+ return false;
+ } else
+ return false;
+ return true;
+}
+
+bool
+DependencySplitter::parse(const char * reldepStr)
+{
+ enum { NAME = 1, CMP_TYPE = 2, EVR = 3, _LAST_ };
+ auto matchResult = RELDEP_REGEX.match(reldepStr, false, _LAST_);
+ if (!matchResult.isMatched() || matchResult.getMatchedLen(NAME) == 0) {
+ return false;
+ }
+ name = matchResult.getMatchedString(NAME);
+ evr = matchResult.getMatchedString(EVR);
+ cmpType = 0;
+ int evrLen = matchResult.getMatchedLen(EVR);
+ int cmpTypeLen = matchResult.getMatchedLen(CMP_TYPE);
+ if (cmpTypeLen < 1) {
+ if (evrLen > 0) {
+ // name contains the space char, e.g. filename like "hello world.jpg"
+ evr.clear();
+ name = reldepStr;
+ }
+ return true;
+ }
+ if (evrLen < 1)
+ return false;
+
+ return getCmpFlags(&cmpType, matchResult.getMatchedString(CMP_TYPE));
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_DEPENDENCY_SPLITTER_HPP
+#define LIBDNF_DEPENDENCY_SPLITTER_HPP
+
+#include <string>
+
+#include "../dnf-types.h"
+
+namespace libdnf {
+
+struct DependencySplitter
+{
+public:
+ /**
+ * @brief Parse realdep char* into thee elements (name, evr, and comparison type), and transforms
+ * into int (HY_EQ, HY_LT, HY_GT, and their combinations).
+ *
+ * @param reldepStr p_reldepStr: Char * that represent reldep
+ * @return bool - true if parsing was succesful
+ */
+ bool parse(const char * reldepStr);
+ const std::string & getName() const noexcept;
+ const char * getNameCStr() const noexcept;
+ const std::string & getEVR() const noexcept;
+ const char * getEVRCStr() const noexcept;
+ int getCmpType() const noexcept;
+
+private:
+ std::string name;
+ std::string evr;
+ int cmpType{0};
+};
+
+inline const std::string & DependencySplitter::getName() const noexcept
+{
+ return name;
+}
+
+inline const std::string & DependencySplitter::getEVR() const noexcept
+{
+ return evr;
+}
+
+inline int DependencySplitter::getCmpType() const noexcept
+{
+ return cmpType;
+}
+
+inline const char * DependencySplitter::getNameCStr() const noexcept
+{
+ return name.empty() ? NULL : name.c_str();
+}
+
+inline const char * DependencySplitter::getEVRCStr() const noexcept
+{
+ return evr.empty() ? NULL : evr.c_str();
+}
+
+}
+
+#endif // LIBDNF_DEPENDENCY_SPLITTER_HPP
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_REPO_PRIVATE_HPP
+#define _LIBDNF_REPO_PRIVATE_HPP
+
+#include "Crypto.hpp"
+#include "Repo.hpp"
+#include "../dnf-utils.h"
+#include "../hy-iutil.h"
+#include "../hy-util-private.hpp"
+#include "../hy-types.h"
+
+#include <utils.hpp>
+
+#include <librepo/librepo.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <solv/chksum.h>
+#include <solv/repo.h>
+#include <solv/util.h>
+
+#include <cctype>
+#include <map>
+#include <mutex>
+#include <set>
+
+#include <string.h>
+#include <time.h>
+
+#define MD_TYPE_PRIMARY "primary"
+#define MD_TYPE_FILELISTS "filelists"
+#define MD_TYPE_PRESTODELTA "prestodelta"
+#define MD_TYPE_GROUP_GZ "group_gz"
+#define MD_TYPE_GROUP "group"
+#define MD_TYPE_UPDATEINFO "updateinfo"
+#define MD_TYPE_MODULES "modules"
+/* "other" in this context is not a generic "any other metadata", but real metadata type named "other"
+ * containing changelogs for packages */
+#define MD_TYPE_OTHER "other"
+
+enum _hy_repo_state {
+ _HY_NEW,
+ _HY_LOADED_FETCH,
+ _HY_LOADED_CACHE,
+ _HY_WRITTEN
+};
+
+namespace std {
+
+template<>
+struct default_delete<LrHandle> {
+ void operator()(LrHandle * ptr) noexcept { lr_handle_free(ptr); }
+};
+
+} // namespace std
+
+namespace libdnf {
+
+typedef ::Repo LibsolvRepo;
+
+class Repo::Impl {
+public:
+ Impl(Repo & owner, const std::string & id, Type type, std::unique_ptr<ConfigRepo> && conf);
+ ~Impl();
+
+ bool load();
+ bool loadCache(bool throwExcept, bool ignoreMissing=false);
+ void downloadMetadata(const std::string & destdir);
+ bool isInSync();
+ void fetch(const std::string & destdir, std::unique_ptr<LrHandle> && h);
+ std::string getCachedir() const;
+ std::string getPersistdir() const;
+ time_t getSystemEpoch() const;
+ int getAge() const;
+ void expire();
+ bool isExpired() const;
+ int getExpiresIn() const;
+ void downloadUrl(const char * url, int fd);
+ void addCountmeFlag(LrHandle *handle);
+ void setHttpHeaders(const char * headers[]);
+ const char * const * getHttpHeaders() const;
+ const std::string & getMetadataPath(const std::string &metadataType) const;
+
+ std::unique_ptr<LrHandle> lrHandleInitBase();
+ std::unique_ptr<LrHandle> lrHandleInitLocal();
+ std::unique_ptr<LrHandle> lrHandleInitRemote(const char *destdir);
+
+ void attachLibsolvRepo(LibsolvRepo * libsolvRepo);
+ void detachLibsolvRepo();
+
+ // Converts configuration string of proxy authorization methods to librepo enum.
+ static LrAuth stringToProxyAuthMethods(const std::string & proxy_auth_method) noexcept;
+
+ std::string id;
+ Type type;
+ std::unique_ptr<ConfigRepo> conf;
+
+ char ** mirrors{nullptr};
+ int maxMirrorTries{0}; // try them all
+ // 0 forces expiration on the next call to load(), -1 means undefined value
+ int timestamp;
+ int maxTimestamp{0};
+ bool preserveRemoteTime{false};
+ bool fresh{false};
+ std::string repomdFn;
+ std::set<std::string> additionalMetadata;
+ std::string revision;
+ std::vector<std::string> content_tags;
+ std::vector<std::pair<std::string, std::string>> distro_tags;
+ std::vector<std::pair<std::string, std::string>> metadata_locations;
+ unsigned char checksum[CHKSUM_BYTES];
+ bool useIncludes{false};
+ bool loadMetadataOther;
+ std::map<std::string, std::string> substitutions;
+
+ std::unique_ptr<RepoCB> callbacks;
+ std::string repoFilePath;
+ LrHandle * getCachedHandle();
+
+ SyncStrategy syncStrategy;
+ std::map<std::string, std::string> metadataPaths;
+
+ LibsolvRepo * libsolvRepo{nullptr};
+ bool needs_internalizing{false};
+ int nrefs{1};
+
+ enum _hy_repo_state state_main{_HY_NEW};
+ enum _hy_repo_state state_filelists{_HY_NEW};
+ enum _hy_repo_state state_presto{_HY_NEW};
+ enum _hy_repo_state state_updateinfo{_HY_NEW};
+ enum _hy_repo_state state_other{_HY_NEW};
+ Id filenames_repodata{0};
+ Id presto_repodata{0};
+ Id updateinfo_repodata{0};
+ Id other_repodata{0};
+ int load_flags{0};
+ /* the following three elements are needed for repo rewriting */
+ int main_nsolvables{0};
+ int main_nrepodata{0};
+ int main_end{0};
+
+ // Lock attachLibsolvRepo(), detachLibsolvRepo() and hy_repo_free() to ensure atomic behavior
+ // in threaded environment such as PackageKit.
+ std::mutex attachLibsolvMutex;
+
+private:
+ Repo * owner;
+ std::unique_ptr<LrResult> lrHandlePerform(LrHandle * handle, const std::string & destDirectory,
+ bool setGPGHomeDir);
+ bool isMetalinkInSync();
+ bool isRepomdInSync();
+ void resetMetadataExpired();
+ std::vector<Key> retrieve(const std::string & url);
+ void importRepoKeys();
+
+ static int progressCB(void * data, double totalToDownload, double downloaded);
+ static void fastestMirrorCB(void * data, LrFastestMirrorStages stage, void *ptr);
+ static int mirrorFailureCB(void * data, const char * msg, const char * url, const char * metadata);
+
+ bool expired;
+ std::unique_ptr<LrHandle> handle;
+ std::unique_ptr<char*[], std::function<void(char **)>> httpHeaders{nullptr, [](char ** ptr)
+ {
+ for (auto item = ptr; *item; ++item)
+ delete[] *item;
+ delete[] ptr;
+ }};
+ bool endsWith(std::string const &str, std::string const &ending) const;
+ std::string getHash() const;
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define METADATA_RELATIVE_DIR "repodata"
+#define PACKAGES_RELATIVE_DIR "packages"
+#define METALINK_FILENAME "metalink.xml"
+#define MIRRORLIST_FILENAME "mirrorlist"
+#define RECOGNIZED_CHKSUMS {"sha512", "sha256"}
+
+#include "../log.hpp"
+#include "Repo-private.hpp"
+#include "../dnf-utils.h"
+#include "../dnf-context.hpp"
+#include "../hy-iutil.h"
+#include "../hy-repo-private.hpp"
+#include "../hy-util-private.hpp"
+#include "../hy-iutil-private.hpp"
+#include "../hy-types.h"
+#include "libdnf/utils/File.hpp"
+#include "libdnf/utils/utils.hpp"
+#include "libdnf/utils/os-release.hpp"
+#include "libdnf/utils/url-encode.hpp"
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "utils.hpp"
+
+#include <librepo/librepo.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include <solv/chksum.h>
+#include <solv/repo.h>
+#include <solv/util.h>
+
+#include <array>
+#include <atomic>
+#include <cctype>
+#include <cerrno>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <set>
+#include <sstream>
+#include <system_error>
+#include <type_traits>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <glib.h>
+
+//
+// COUNTME CONSTANTS
+//
+// width of the sliding time window (in seconds)
+const int COUNTME_WINDOW = 7*24*60*60; // 1 week
+// starting point of the sliding time window relative to the UNIX epoch
+// allows for aligning the window with a specific weekday
+const int COUNTME_OFFSET = 345600; // Monday (1970-01-05 00:00:00 UTC)
+// estimated number of metalink requests sent over the window
+// used to generate the probability distribution of counting events
+const int COUNTME_BUDGET = 4; // metadata_expire defaults to 2 days
+// cookie file name
+const std::string COUNTME_COOKIE = "countme";
+// cookie file format version
+const int COUNTME_VERSION = 0;
+// longevity buckets that we report in the flag
+// example: {A, B, C} defines 4 buckets [0, A), [A, B), [B, C), [C, infinity)
+// where each letter represents a window step (starting from 0)
+const std::array<const int, 3> COUNTME_BUCKETS = { {2, 5, 25} };
+
+namespace std {
+
+template<>
+struct default_delete<GError> {
+ void operator()(GError * ptr) noexcept { g_error_free(ptr); }
+};
+
+template<>
+struct default_delete<LrResult> {
+ void operator()(LrResult * ptr) noexcept { lr_result_free(ptr); }
+};
+
+template<>
+struct default_delete<LrPackageTarget> {
+ void operator()(LrPackageTarget * ptr) noexcept { lr_packagetarget_free(ptr); }
+};
+
+} // namespace std
+
+namespace libdnf {
+
+class LrExceptionWithSourceUrl : public LrException {
+public:
+ LrExceptionWithSourceUrl(int code, const std::string & msg, const std::string & sourceUrl)
+ : LrException(code, msg), sourceUrl(sourceUrl) {}
+ const std::string & getSourceUrl() const { return sourceUrl; }
+private:
+ std::string sourceUrl;
+};
+
+static void throwException(std::unique_ptr<GError> && err)
+{
+ throw LrException(err->code, err->message);
+}
+
+template<typename T>
+inline static void handleSetOpt(LrHandle * handle, LrHandleOption option, T value)
+{
+ GError * errP{nullptr};
+ if (!lr_handle_setopt(handle, &errP, option, value)) {
+ throwException(std::unique_ptr<GError>(errP));
+ }
+}
+
+inline static void handleGetInfo(LrHandle * handle, LrHandleInfoOption option, void * value)
+{
+ GError * errP{nullptr};
+ if (!lr_handle_getinfo(handle, &errP, option, value)) {
+ throwException(std::unique_ptr<GError>(errP));
+ }
+}
+
+template<typename T>
+inline static void resultGetInfo(LrResult * result, LrResultInfoOption option, T value)
+{
+ GError * errP{nullptr};
+ if (!lr_result_getinfo(result, &errP, option, value)) {
+ throwException(std::unique_ptr<GError>(errP));
+ }
+}
+
+/* Callback stuff */
+
+int RepoCB::progress(double totalToDownload, double downloaded) { return 0; }
+void RepoCB::fastestMirror(FastestMirrorStage stage, const char * ptr) {}
+int RepoCB::handleMirrorFailure(const char * msg, const char * url, const char * metadata) { return 0; }
+
+bool RepoCB::repokeyImport(const std::string & id, const std::string & userId,
+ const std::string & fingerprint, const std::string & url, long int timestamp)
+{
+ return true;
+}
+
+
+// Map string from config option proxy_auth_method to librepo LrAuth value
+static constexpr struct {
+ const char * name;
+ LrAuth code;
+} PROXYAUTHMETHODS[] = {
+ {"none", LR_AUTH_NONE},
+ {"basic", LR_AUTH_BASIC},
+ {"digest", LR_AUTH_DIGEST},
+ {"negotiate", LR_AUTH_NEGOTIATE},
+ {"ntlm", LR_AUTH_NTLM},
+ {"digest_ie", LR_AUTH_DIGEST_IE},
+ {"ntlm_wb", LR_AUTH_NTLM_WB},
+ {"any", LR_AUTH_ANY}
+};
+
+bool Repo::Impl::endsWith(const std::string &str, const std::string &ending) const {
+ if (str.length() >= ending.length())
+ return (str.compare(str.length() - ending.length(), ending.length(), ending) == 0);
+ else
+ return false;
+}
+
+const std::string & Repo::Impl::getMetadataPath(const std::string &metadataType) const {
+// auto logger(Log::getLogger());
+ static const std::string empty;
+ std::string lookupMetadataType = metadataType;
+ if (conf->getMainConfig().zchunk().getValue()) {
+ if(!endsWith(metadataType, "_zck"))
+ lookupMetadataType = metadataType + "_zck";
+ }
+ auto it = metadataPaths.find(lookupMetadataType);
+ if(it == metadataPaths.end() && lookupMetadataType != metadataType)
+ it = metadataPaths.find(metadataType);
+ auto & ret = (it != metadataPaths.end()) ? it->second : empty;
+// if (ret.empty())
+// logger->debug(tfm::format("not found \"%s\" for: %s", metadataType, conf->name().getValue()));
+ return ret;
+}
+
+int Repo::Impl::progressCB(void * data, double totalToDownload, double downloaded)
+{
+ if (!data)
+ return 0;
+ auto cbObject = static_cast<RepoCB *>(data);
+ return cbObject->progress(totalToDownload, downloaded);
+}
+
+void Repo::Impl::fastestMirrorCB(void * data, LrFastestMirrorStages stage, void *ptr)
+{
+ if (!data)
+ return;
+ auto cbObject = static_cast<RepoCB *>(data);
+ const char * msg;
+ std::string msgString;
+ if (ptr) {
+ switch (stage) {
+ case LR_FMSTAGE_CACHELOADING:
+ case LR_FMSTAGE_CACHELOADINGSTATUS:
+ case LR_FMSTAGE_STATUS:
+ msg = static_cast<const char *>(ptr);
+ break;
+ case LR_FMSTAGE_DETECTION:
+ msgString = std::to_string(*((long *)ptr));
+ msg = msgString.c_str();
+ break;
+ default:
+ msg = nullptr;
+ }
+ } else
+ msg = nullptr;
+ cbObject->fastestMirror(static_cast<RepoCB::FastestMirrorStage>(stage), msg);
+}
+
+int Repo::Impl::mirrorFailureCB(void * data, const char * msg, const char * url, const char * metadata)
+{
+ if (!data)
+ return 0;
+ auto cbObject = static_cast<RepoCB *>(data);
+ return cbObject->handleMirrorFailure(msg, url, metadata);
+};
+
+
+/**
+* @brief Format user password string
+*
+* Returns user and password in user:password form. If quote is True,
+* special characters in user and password are URL encoded.
+*
+* @param user Username
+* @param passwd Password
+* @param encode If quote is True, special characters in user and password are URL encoded.
+* @return User and password in user:password form
+*/
+static std::string formatUserPassString(const std::string & user, const std::string & passwd, bool encode)
+{
+ if (encode)
+ return urlEncode(user) + ":" + urlEncode(passwd);
+ else
+ return user + ":" + passwd;
+}
+
+Repo::Impl::Impl(Repo & owner, const std::string & id, Type type, std::unique_ptr<ConfigRepo> && conf)
+: id(id), type(type), conf(std::move(conf)), timestamp(-1), loadMetadataOther(false)
+, syncStrategy(SyncStrategy::TRY_CACHE), owner(&owner), expired(false) {}
+
+Repo::Impl::~Impl()
+{
+ g_strfreev(mirrors);
+ if (libsolvRepo)
+ libsolvRepo->appdata = nullptr;
+}
+
+Repo::Repo(const std::string & id, std::unique_ptr<ConfigRepo> && conf, Repo::Type type)
+{
+ if (type == Type::AVAILABLE) {
+ auto idx = verifyId(id);
+ if (idx >= 0) {
+ std::string msg = tfm::format(
+ ("Invalid repository id \"%s\": invalid character '%s' at position %d."),
+ id, id[idx], idx + 1);
+ throw RepoError(msg);
+ }
+ }
+ pImpl.reset(new Impl(*this, id, type, std::move(conf)));
+}
+
+Repo::~Repo() = default;
+
+void Repo::setCallbacks(std::unique_ptr<RepoCB> && callbacks)
+{
+ pImpl->callbacks = std::move(callbacks);
+}
+
+int Repo::verifyId(const std::string & id)
+{
+ auto idx = id.find_first_not_of(REPOID_CHARS);
+ return idx == id.npos ? -1 : idx;
+}
+
+void Repo::verify() const
+{
+ if (pImpl->conf->baseurl().empty() &&
+ (pImpl->conf->metalink().empty() || pImpl->conf->metalink().getValue().empty()) &&
+ (pImpl->conf->mirrorlist().empty() || pImpl->conf->mirrorlist().getValue().empty()))
+ throw RepoError(tfm::format(_("Repository %s has no mirror or baseurl set."), pImpl->id));
+
+ const auto & type = pImpl->conf->type().getValue();
+ const char * supportedRepoTypes[]{"rpm-md", "rpm", "repomd", "rpmmd", "yum", "YUM"};
+ if (!type.empty()) {
+ for (auto supported : supportedRepoTypes) {
+ if (type == supported)
+ return;
+ }
+ throw RepoError(tfm::format(_("Repository '%s' has unsupported type: 'type=%s', skipping."),
+ pImpl->id, type));
+ }
+}
+
+ConfigRepo * Repo::getConfig() noexcept
+{
+ return pImpl->conf.get();
+}
+
+const std::string & Repo::getId() const noexcept
+{
+ return pImpl->id;
+}
+
+void Repo::enable()
+{
+ pImpl->conf->enabled().set(Option::Priority::RUNTIME, true);
+}
+
+void Repo::disable()
+{
+ pImpl->conf->enabled().set(Option::Priority::RUNTIME, false);
+}
+
+bool Repo::isEnabled() const
+{
+ return pImpl->conf->enabled().getValue();
+}
+
+bool Repo::isLocal() const
+{
+ auto & conf = pImpl->conf;
+ if ((!conf->metalink().empty() && !conf->metalink().getValue().empty()) ||
+ (!conf->mirrorlist().empty() && !conf->mirrorlist().getValue().empty()))
+ return false;
+ if (!conf->baseurl().getValue().empty() && conf->baseurl().getValue()[0].compare(0, 7, "file://") == 0)
+ return true;
+ return false;
+}
+
+std::string Repo::getLocalBaseurl() const
+{
+ if (!isLocal()) {
+ throw Exception("Invalid call getLocalBaseurl() on a non-local repository.");
+ }
+
+ // isLocal() already ensured the first item in the list starts with "file://"
+ return urlDecode(pImpl->conf->baseurl().getValue()[0].substr(7));
+}
+
+bool Repo::load() { return pImpl->load(); }
+bool Repo::loadCache(bool throwExcept, bool ignoreMissing) { return pImpl->loadCache(throwExcept, ignoreMissing); }
+void Repo::downloadMetadata(const std::string & destdir) { pImpl->downloadMetadata(destdir); }
+bool Repo::getUseIncludes() const { return pImpl->useIncludes; }
+void Repo::setUseIncludes(bool enabled) { pImpl->useIncludes = enabled; }
+bool Repo::getLoadMetadataOther() const { return pImpl->loadMetadataOther; }
+void Repo::setLoadMetadataOther(bool value) { pImpl->loadMetadataOther = value; }
+int Repo::getCost() const { return pImpl->conf->cost().getValue(); }
+int Repo::getPriority() const { return pImpl->conf->priority().getValue(); }
+std::string Repo::getCompsFn() {
+ auto tmp = pImpl->getMetadataPath(MD_TYPE_GROUP_GZ);
+ if (tmp.empty())
+ tmp = pImpl->getMetadataPath(MD_TYPE_GROUP);
+ return tmp;
+}
+
+
+#ifdef MODULEMD
+std::string Repo::getModulesFn() { return pImpl->getMetadataPath(MD_TYPE_MODULES); }
+#endif
+
+int Repo::getAge() const { return pImpl->getAge(); }
+void Repo::expire() { pImpl->expire(); }
+bool Repo::isExpired() const { return pImpl->isExpired(); }
+int Repo::getExpiresIn() const { return pImpl->getExpiresIn(); }
+
+void Repo::setSubstitutions(const std::map<std::string, std::string> & substitutions)
+{
+ pImpl->substitutions = substitutions;
+}
+
+void Repo::addMetadataTypeToDownload(const std::string &metadataType)
+{
+ pImpl->additionalMetadata.insert(metadataType);
+}
+
+void Repo::removeMetadataTypeFromDownload(const std::string &metadataType)
+{
+ pImpl->additionalMetadata.erase(metadataType);
+}
+
+std::string Repo::getMetadataPath(const std::string &metadataType)
+{
+ return pImpl->getMetadataPath(metadataType);
+}
+
+std::string Repo::getMetadataContent(const std::string &metadataType)
+{
+ auto path = getMetadataPath(metadataType);
+ if (path.empty()) return "";
+
+ auto mdfile = File::newFile(path);
+ mdfile->open("r");
+ const auto &content = mdfile->getContent();
+ mdfile->close();
+ return content;
+}
+
+std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitBase()
+{
+ std::unique_ptr<LrHandle> h(lr_handle_init());
+ std::vector<const char *> dlist = {MD_TYPE_PRIMARY, MD_TYPE_PRESTODELTA, MD_TYPE_GROUP_GZ, MD_TYPE_UPDATEINFO};
+
+ auto & optionalMetadataTypes = conf->getMainConfig().optional_metadata_types().getValue();
+ auto loadFilelists = std::find(optionalMetadataTypes.begin(), optionalMetadataTypes.end(), "filelists") !=
+ optionalMetadataTypes.end();
+
+#ifdef MODULEMD
+ dlist.push_back(MD_TYPE_MODULES);
+#endif
+ if (loadFilelists) {
+ dlist.push_back(MD_TYPE_FILELISTS);
+ }
+ if (loadMetadataOther) {
+ dlist.push_back(MD_TYPE_OTHER);
+ }
+ for (auto &item : additionalMetadata) {
+ dlist.push_back(item.c_str());
+ }
+ dlist.push_back(NULL);
+ handleSetOpt(h.get(), LRO_PRESERVETIME, static_cast<long>(preserveRemoteTime));
+ handleSetOpt(h.get(), LRO_REPOTYPE, LR_YUMREPO);
+ handleSetOpt(h.get(), LRO_USERAGENT, conf->user_agent().getValue().c_str());
+ handleSetOpt(h.get(), LRO_YUMDLIST, dlist.data());
+ handleSetOpt(h.get(), LRO_INTERRUPTIBLE, 1L);
+ handleSetOpt(h.get(), LRO_GPGCHECK, conf->repo_gpgcheck().getValue());
+ handleSetOpt(h.get(), LRO_MAXMIRRORTRIES, static_cast<long>(maxMirrorTries));
+ handleSetOpt(h.get(), LRO_MAXPARALLELDOWNLOADS,
+ conf->max_parallel_downloads().getValue());
+ handleSetOpt(h.get(), LRO_MAXDOWNLOADSPERMIRROR,
+ conf->max_downloads_per_mirror().getValue());
+
+ LrUrlVars * vars = NULL;
+ vars = lr_urlvars_set(vars, MD_TYPE_GROUP_GZ, MD_TYPE_GROUP);
+ handleSetOpt(h.get(), LRO_YUMSLIST, vars);
+
+ return h;
+}
+
+std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitLocal()
+{
+ std::unique_ptr<LrHandle> h(lrHandleInitBase());
+
+ LrUrlVars * vars = NULL;
+ for (const auto & item : substitutions)
+ vars = lr_urlvars_set(vars, item.first.c_str(), item.second.c_str());
+ handleSetOpt(h.get(), LRO_VARSUB, vars);
+ auto cachedir = getCachedir();
+ handleSetOpt(h.get(), LRO_DESTDIR, cachedir.c_str());
+ const char *urls[] = {cachedir.c_str(), NULL};
+ handleSetOpt(h.get(), LRO_URLS, urls);
+ handleSetOpt(h.get(), LRO_LOCAL, 1L);
+#ifdef LRO_SUPPORTS_CACHEDIR
+ /* If zchunk is enabled, set librepo cache dir */
+ if (conf->getMainConfig().zchunk().getValue()) {
+ if (conf->basecachedir().empty()) {
+ throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
+ }
+ handleSetOpt(h.get(), LRO_CACHEDIR, conf->basecachedir().getValue().c_str());
+ }
+#endif
+ return h;
+}
+
+template<typename ConfigT>
+static void setHandle(LrHandle * h, ConfigT & config, const char * repoId = nullptr) {
+ auto & ipResolve = config.ip_resolve().getValue();
+ if (ipResolve == "ipv4")
+ handleSetOpt(h, LRO_IPRESOLVE, LR_IPRESOLVE_V4);
+ else if (ipResolve == "ipv6")
+ handleSetOpt(h, LRO_IPRESOLVE, LR_IPRESOLVE_V6);
+
+ auto minrate = config.minrate().getValue();
+ handleSetOpt(h, LRO_LOWSPEEDLIMIT, static_cast<long>(minrate));
+
+ auto maxspeed = config.throttle().getValue();
+ if (maxspeed > 0 && maxspeed <= 1)
+ maxspeed *= config.bandwidth().getValue();
+ if (maxspeed != 0 && maxspeed < minrate)
+ throw RepoError(_("Maximum download speed is lower than minimum. "
+ "Please change configuration of minrate or throttle"));
+ handleSetOpt(h, LRO_MAXSPEED, static_cast<int64_t>(maxspeed));
+
+ long timeout = config.timeout().getValue();
+ if (timeout > 0) {
+ handleSetOpt(h, LRO_CONNECTTIMEOUT, timeout);
+ handleSetOpt(h, LRO_LOWSPEEDTIME, timeout);
+ } else {
+ handleSetOpt(h, LRO_CONNECTTIMEOUT, LRO_CONNECTTIMEOUT_DEFAULT);
+ handleSetOpt(h, LRO_LOWSPEEDTIME, LRO_LOWSPEEDTIME_DEFAULT);
+ }
+
+ // setup username/password if needed
+ auto userpwd = config.username().getValue();
+ if (!userpwd.empty()) {
+ // TODO Use URL encoded form, needs support in librepo
+ userpwd = formatUserPassString(userpwd, config.password().getValue(), false);
+ handleSetOpt(h, LRO_USERPWD, userpwd.c_str());
+ }
+
+ if (!config.proxy().empty() && !config.proxy().getValue().empty())
+ handleSetOpt(h, LRO_PROXY, config.proxy().getValue().c_str());
+
+ //set proxy authorization method
+ auto proxyAuthMethods = Repo::Impl::stringToProxyAuthMethods(config.proxy_auth_method().getValue());
+ handleSetOpt(h, LRO_PROXYAUTHMETHODS, static_cast<long>(proxyAuthMethods));
+
+ // setup proxy username/password if needed
+ if (!config.proxy_username().empty()) {
+ auto userpwd = config.proxy_username().getValue();
+ if (!userpwd.empty()) {
+ if (config.proxy_password().empty()) {
+ if (repoId)
+ throw RepoError(tfm::format(_("repo '%s': 'proxy_username' is set but not 'proxy_password'"), repoId));
+ else
+ throw RepoError(_("'proxy_username' is set but not 'proxy_password'"));
+ }
+ userpwd = formatUserPassString(userpwd, config.proxy_password().getValue(), true);
+ handleSetOpt(h, LRO_PROXYUSERPWD, userpwd.c_str());
+ }
+ }
+
+ // setup ssl stuff
+ if (!config.sslcacert().getValue().empty())
+ handleSetOpt(h, LRO_SSLCACERT, config.sslcacert().getValue().c_str());
+ if (!config.sslclientcert().getValue().empty())
+ handleSetOpt(h, LRO_SSLCLIENTCERT, config.sslclientcert().getValue().c_str());
+ if (!config.sslclientkey().getValue().empty())
+ handleSetOpt(h, LRO_SSLCLIENTKEY, config.sslclientkey().getValue().c_str());
+ long sslverify = config.sslverify().getValue() ? 1L : 0L;
+ handleSetOpt(h, LRO_SSLVERIFYHOST, sslverify);
+ handleSetOpt(h, LRO_SSLVERIFYPEER, sslverify);
+ handleSetOpt(h, LRO_SSLVERIFYSTATUS, config.sslverifystatus().getValue() ? 1L : 0L);
+
+ // setup proxy ssl stuff
+ if (!config.proxy_sslcacert().getValue().empty())
+ handleSetOpt(h, LRO_PROXY_SSLCACERT, config.proxy_sslcacert().getValue().c_str());
+ if (!config.proxy_sslclientcert().getValue().empty())
+ handleSetOpt(h, LRO_PROXY_SSLCLIENTCERT, config.proxy_sslclientcert().getValue().c_str());
+ if (!config.proxy_sslclientkey().getValue().empty())
+ handleSetOpt(h, LRO_PROXY_SSLCLIENTKEY, config.proxy_sslclientkey().getValue().c_str());
+ long proxy_sslverify = config.proxy_sslverify().getValue() ? 1L : 0L;
+ handleSetOpt(h, LRO_PROXY_SSLVERIFYHOST, proxy_sslverify);
+ handleSetOpt(h, LRO_PROXY_SSLVERIFYPEER, proxy_sslverify);
+}
+
+std::unique_ptr<LrHandle> Repo::Impl::lrHandleInitRemote(const char *destdir)
+{
+ std::unique_ptr<LrHandle> h(lrHandleInitBase());
+ handleSetOpt(h.get(), LRO_HTTPHEADER, httpHeaders.get());
+
+ LrUrlVars * vars = NULL;
+ for (const auto & item : substitutions)
+ vars = lr_urlvars_set(vars, item.first.c_str(), item.second.c_str());
+ handleSetOpt(h.get(), LRO_VARSUB, vars);
+
+ handleSetOpt(h.get(), LRO_DESTDIR, destdir);
+
+ enum class Source {NONE, METALINK, MIRRORLIST} source{Source::NONE};
+ std::string tmp;
+ if (!conf->metalink().empty() && !(tmp=conf->metalink().getValue()).empty())
+ source = Source::METALINK;
+ else if (!conf->mirrorlist().empty() && !(tmp=conf->mirrorlist().getValue()).empty())
+ source = Source::MIRRORLIST;
+ if (source != Source::NONE) {
+ handleSetOpt(h.get(), LRO_PROGRESSDATA, callbacks.get());
+ if (source == Source::METALINK)
+ handleSetOpt(h.get(), LRO_METALINKURL, tmp.c_str());
+ else {
+ handleSetOpt(h.get(), LRO_MIRRORLISTURL, tmp.c_str());
+ // YUM-DNF compatibility hack. YUM guessed by content of keyword "metalink" if
+ // mirrorlist is really mirrorlist or metalink)
+ if (tmp.find("metalink") != tmp.npos)
+ handleSetOpt(h.get(), LRO_METALINKURL, tmp.c_str());
+ }
+ handleSetOpt(h.get(), LRO_FASTESTMIRROR, conf->fastestmirror().getValue() ? 1L : 0L);
+ if (conf->basecachedir().empty()) {
+ throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
+ }
+ auto fastestMirrorCacheDir = conf->basecachedir().getValue();
+ if (fastestMirrorCacheDir.back() != '/')
+ fastestMirrorCacheDir.push_back('/');
+ fastestMirrorCacheDir += "fastestmirror.cache";
+ handleSetOpt(h.get(), LRO_FASTESTMIRRORCACHE, fastestMirrorCacheDir.c_str());
+ }
+
+ if (!conf->baseurl().getValue().empty()) {
+ size_t len = conf->baseurl().getValue().size();
+ const char * urls[len + 1];
+ for (size_t idx = 0; idx < len; ++idx)
+ urls[idx] = conf->baseurl().getValue()[idx].c_str();
+ urls[len] = nullptr;
+ handleSetOpt(h.get(), LRO_URLS, urls);
+ }
+
+ if (source == Source::NONE && conf->baseurl().getValue().empty())
+ throw RepoError(tfm::format(_("Cannot find a valid baseurl for repo: %s"), id));
+
+ handleSetOpt(h.get(), LRO_HMFCB, static_cast<LrHandleMirrorFailureCb>(mirrorFailureCB));
+ handleSetOpt(h.get(), LRO_PROGRESSCB, static_cast<LrProgressCb>(progressCB));
+ handleSetOpt(h.get(), LRO_PROGRESSDATA, callbacks.get());
+ handleSetOpt(h.get(), LRO_FASTESTMIRRORCB, static_cast<LrFastestMirrorCb>(fastestMirrorCB));
+ handleSetOpt(h.get(), LRO_FASTESTMIRRORDATA, callbacks.get());
+
+#ifdef LRO_SUPPORTS_CACHEDIR
+ /* If zchunk is enabled, set librepo cache dir */
+ if (conf->getMainConfig().zchunk().getValue()) {
+ if (conf->basecachedir().empty()) {
+ throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
+ }
+ handleSetOpt(h.get(), LRO_CACHEDIR, conf->basecachedir().getValue().c_str());
+ }
+#endif
+
+ setHandle(h.get(), *conf, id.c_str());
+
+ return h;
+}
+
+
+// download key from URL
+std::vector<Key> Repo::Impl::retrieve(const std::string & url)
+{
+ auto logger(Log::getLogger());
+ char tmpKeyFile[] = "/tmp/repokey.XXXXXX";
+ auto fd = mkstemp(tmpKeyFile);
+ if (fd == -1) {
+ auto msg = tfm::format("Error creating temporary file \"%s\": %s",
+ tmpKeyFile, std::system_category().message(errno));
+ logger->debug(msg);
+ throw LrException(LRE_GPGERROR, msg);
+ }
+ unlink(tmpKeyFile);
+ Finalizer tmpFileCloser([fd](){
+ close(fd);
+ });
+
+ try {
+ downloadUrl(url.c_str(), fd);
+ }
+ catch (const LrExceptionWithSourceUrl & e) {
+ auto msg = tfm::format(_("Failed to retrieve GPG key for repo '%s': %s"), id, e.what());
+ throw RepoError(msg);
+ }
+ lseek(fd, SEEK_SET, 0);
+ auto keyInfos = Key::keysFromFd(fd);
+ for (auto & key : keyInfos)
+ key.setUrl(url);
+ return keyInfos;
+}
+
+
+void Repo::Impl::importRepoKeys()
+{
+ auto logger(Log::getLogger());
+
+ auto gpgDir = getCachedir() + "/pubring";
+ auto knownKeys = keyidsFromPubring(gpgDir);
+ for (const auto & gpgkeyUrl : conf->gpgkey().getValue()) {
+ auto keyInfos = retrieve(gpgkeyUrl);
+ for (auto & keyInfo : keyInfos) {
+ if (std::find(knownKeys.begin(), knownKeys.end(), keyInfo.getId()) != knownKeys.end()) {
+ logger->debug(tfm::format(_("repo %s: 0x%s already imported"), id, keyInfo.getId()));
+ continue;
+ }
+
+ if (callbacks) {
+ if (!callbacks->repokeyImport(keyInfo.getId(), keyInfo.getUserId(), keyInfo.getFingerprint(),
+ keyInfo.getUrl(), keyInfo.getTimestamp()))
+ continue;
+ }
+
+ struct stat sb;
+ if (stat(gpgDir.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
+ int res = mkdir(gpgDir.c_str(), 0777);
+ if (res != 0 && errno != EEXIST) {
+ auto msg = tfm::format(_("Failed to create directory \"%s\": %d - %s"),
+ gpgDir, errno, strerror(errno));
+ throw RepoError(msg);
+ }
+ }
+
+ importKeyToPubring(keyInfo.getAsciiArmoredKey(), gpgDir);
+
+ logger->debug(tfm::format(_("repo %s: imported key 0x%s."), id, keyInfo.getId()));
+ }
+
+ }
+}
+
+std::unique_ptr<LrResult> Repo::Impl::lrHandlePerform(LrHandle * handle, const std::string & destDirectory,
+ bool setGPGHomeDir)
+{
+ if (setGPGHomeDir) {
+ auto pubringdir = getCachedir() + "/pubring";
+ handleSetOpt(handle, LRO_GNUPGHOMEDIR, pubringdir.c_str());
+ }
+
+ // Start and end is called only if progress callback is set in handle.
+ LrProgressCb progressFunc;
+ handleGetInfo(handle, LRI_PROGRESSCB, &progressFunc);
+
+ addCountmeFlag(handle);
+
+ std::unique_ptr<LrResult> result;
+ bool ret;
+ bool badGPG = false;
+ do {
+ if (callbacks && progressFunc)
+ callbacks->start(
+ !conf->name().getValue().empty() ? conf->name().getValue().c_str() :
+ (!id.empty() ? id.c_str() : "unknown")
+ );
+
+ GError * errP{nullptr};
+ result.reset(lr_result_init());
+ ret = lr_handle_perform(handle, result.get(), &errP);
+ std::unique_ptr<GError> err(errP);
+
+ if (callbacks && progressFunc)
+ callbacks->end();
+
+ if (ret || badGPG || errP->code != LRE_BADGPG) {
+ if (!ret) {
+ std::string source;
+ if (conf->metalink().empty() || (source=conf->metalink().getValue()).empty()) {
+ if (conf->mirrorlist().empty() || (source=conf->mirrorlist().getValue()).empty()) {
+ bool first = true;
+ for (const auto & url : conf->baseurl().getValue()) {
+ if (first)
+ first = false;
+ else
+ source += ", ";
+ source += url;
+ }
+ }
+ }
+ throw LrExceptionWithSourceUrl(err->code, err->message, source);
+ }
+ break;
+ }
+ badGPG = true;
+ importRepoKeys();
+ dnf_remove_recursive((destDirectory + "/" + METADATA_RELATIVE_DIR).c_str(), NULL);
+ } while (true);
+
+ return result;
+}
+
+bool Repo::Impl::loadCache(bool throwExcept, bool ignoreMissing)
+{
+ std::unique_ptr<LrHandle> h(lrHandleInitLocal());
+ std::unique_ptr<LrResult> r;
+
+ if (ignoreMissing) {
+ handleSetOpt(h.get(), LRO_IGNOREMISSING, 1L);
+ }
+
+ // Fetch data
+ try {
+ r = lrHandlePerform(h.get(), getCachedir(), conf->repo_gpgcheck().getValue());
+ } catch (std::exception & ex) {
+ if (throwExcept)
+ throw;
+ return false;
+ }
+
+ char **mirrors;
+ LrYumRepo *yum_repo;
+ LrYumRepoMd *yum_repomd;
+ handleGetInfo(h.get(), LRI_MIRRORS, &mirrors);
+ resultGetInfo(r.get(), LRR_YUM_REPO, &yum_repo);
+ resultGetInfo(r.get(), LRR_YUM_REPOMD, &yum_repomd);
+
+ // Populate repo
+ repomdFn = yum_repo->repomd;
+ metadataPaths.clear();
+ for (auto *elem = yum_repo->paths; elem; elem = g_slist_next(elem)) {
+ if (elem->data) {
+ auto yumrepopath = static_cast<LrYumRepoPath *>(elem->data);
+ metadataPaths.emplace(yumrepopath->type, yumrepopath->path);
+ }
+ }
+
+ content_tags.clear();
+ for (auto elem = yum_repomd->content_tags; elem; elem = g_slist_next(elem)) {
+ if (elem->data)
+ content_tags.emplace_back(static_cast<const char *>(elem->data));
+ }
+
+ distro_tags.clear();
+ for (auto elem = yum_repomd->distro_tags; elem; elem = g_slist_next(elem)) {
+ if (elem->data) {
+ auto distroTag = static_cast<LrYumDistroTag *>(elem->data);
+ if (distroTag->tag) {
+ std::string cpeid_str;
+ if (distroTag->cpeid) {
+ cpeid_str = distroTag->cpeid;
+ }
+ distro_tags.emplace_back(std::move(cpeid_str), distroTag->tag);
+ }
+ }
+ }
+
+ metadata_locations.clear();
+ for (auto elem = yum_repomd->records; elem; elem = g_slist_next(elem)) {
+ if (elem->data) {
+ auto rec = static_cast<LrYumRepoMdRecord *>(elem->data);
+ metadata_locations.emplace_back(rec->type, rec->location_href);
+ }
+ }
+
+ if (auto cRevision = yum_repomd->revision) {
+ revision = cRevision;
+ }
+ maxTimestamp = lr_yum_repomd_get_highest_timestamp(yum_repomd, NULL);
+
+ // Load timestamp unless explicitly expired
+ if (timestamp != 0) {
+ timestamp = mtime(getMetadataPath(MD_TYPE_PRIMARY).c_str());
+ }
+ g_strfreev(this->mirrors);
+ this->mirrors = mirrors;
+ return true;
+}
+
+void Repo::Impl::addCountmeFlag(LrHandle *handle) {
+ /*
+ * The countme flag will be added once (and only once) in every position of
+ * a sliding time window (COUNTME_WINDOW) that starts at COUNTME_OFFSET and
+ * moves along the time axis, by one length at a time, in such a way that
+ * the current point in time always stays within:
+ *
+ * UNIX epoch now
+ * | |
+ * |---*-----|-----|-----|-----[-*---]---> time
+ * | ~~~~~~~
+ * COUNTME_OFFSET COUNTME_WINDOW
+ *
+ * This is to align the time window with an absolute point in time rather
+ * than the last counting event (which could facilitate tracking across
+ * multiple such events).
+ *
+ * In the below comments, the window's current position will be referred to
+ * as "this window" for brevity.
+ */
+ auto logger(Log::getLogger());
+
+ // Bail out if not counting or not running as root (since the persistdir is
+ // only root-writable)
+ if (!conf->countme().getValue() || getuid() != 0)
+ return;
+
+ // Bail out if not a remote handle
+ long local;
+ handleGetInfo(handle, LRI_LOCAL, &local);
+ if (local)
+ return;
+
+ // Bail out if no metalink or mirrorlist is defined
+ auto & metalink = conf->metalink();
+ auto & mirrorlist = conf->mirrorlist();
+ if ((metalink.empty() || metalink.getValue().empty()) &&
+ (mirrorlist.empty() || mirrorlist.getValue().empty()))
+ return;
+
+ // Load the cookie
+ std::string fname = getPersistdir() + "/" + COUNTME_COOKIE;
+ int ver = COUNTME_VERSION; // file format version (for future use)
+ time_t epoch = 0; // position of first observed window
+ time_t win = COUNTME_OFFSET; // position of last counted window
+ int budget = -1; // budget for this window (-1 = generate)
+ std::ifstream(fname) >> ver >> epoch >> win >> budget;
+
+ // Bail out if the window has not advanced since
+ time_t now = time(NULL);
+ time_t delta = now - win;
+ if (delta < COUNTME_WINDOW) {
+ logger->debug(tfm::format("countme: no event for %s: window already counted", id));
+ return;
+ }
+
+ // Evenly distribute the probability of the counting event over the first N
+ // requests in this window (where N = COUNTME_BUDGET), by defining a random
+ // "budget" of ordinary requests that we first have to spend. This ensures
+ // that no particular request is special and thus no privacy loss is
+ // incurred by adding the flag within N requests.
+ if (budget < 0)
+ budget = numeric::random(1, COUNTME_BUDGET);
+ budget--;
+ if (!budget) {
+ // Budget exhausted, counting!
+
+ // Compute the position of this window
+ win = now - (delta % COUNTME_WINDOW);
+
+ // Compute the epoch from this system's epoch or, if unknown, declare
+ // this window as the epoch (unless stored in the cookie previously).
+ time_t sysepoch = getSystemEpoch();
+ if (sysepoch)
+ epoch = sysepoch - ((sysepoch - COUNTME_OFFSET) % COUNTME_WINDOW);
+ if (!epoch)
+ epoch = win;
+
+ // Window step (0 at epoch)
+ int step = (win - epoch) / COUNTME_WINDOW;
+
+ // Compute the bucket we are in
+ unsigned int i;
+ for (i = 0; i < COUNTME_BUCKETS.size(); ++i)
+ if (step < COUNTME_BUCKETS[i])
+ break;
+ int bucket = i + 1; // Buckets are numbered from 1
+
+ // Set the flag
+ std::string flag = "countme=" + std::to_string(bucket);
+ handleSetOpt(handle, LRO_ONETIMEFLAG, flag.c_str());
+ logger->debug(tfm::format("countme: event triggered for %s: bucket %i", id, bucket));
+
+ // Request a new budget
+ budget = -1;
+ } else {
+ logger->debug(tfm::format("countme: no event for %s: budget to spend: %i", id, budget));
+ }
+
+ // Save the cookie
+ std::ofstream(fname) << COUNTME_VERSION << " " << epoch << " " << win
+ << " " << budget;
+}
+
+// Use metalink to check whether our metadata are still current.
+bool Repo::Impl::isMetalinkInSync()
+{
+ auto logger(Log::getLogger());
+ char tmpdir[] = "/tmp/tmpdir.XXXXXX";
+ if (!mkdtemp(tmpdir)) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"),
+ tmpdir, errTxt));
+ }
+ Finalizer tmpDirRemover([&tmpdir](){
+ dnf_remove_recursive(tmpdir, NULL);
+ });
+
+ std::unique_ptr<LrHandle> h(lrHandleInitRemote(tmpdir));
+
+ handleSetOpt(h.get(), LRO_FETCHMIRRORS, 1L);
+ auto r = lrHandlePerform(h.get(), tmpdir, false);
+ LrMetalink * metalink;
+ handleGetInfo(h.get(), LRI_METALINK, &metalink);
+ if (!metalink) {
+ logger->debug(tfm::format(_("reviving: repo '%s' skipped, no metalink."), id));
+ return false;
+ }
+
+ // check all recognized hashes
+ auto chksumFree = [](Chksum * ptr){solv_chksum_free(ptr, nullptr);};
+ struct hashInfo {
+ const LrMetalinkHash * lrMetalinkHash;
+ std::unique_ptr<Chksum, decltype(chksumFree)> chksum;
+ };
+ std::vector<hashInfo> hashes;
+ for (auto hash = metalink->hashes; hash; hash = hash->next) {
+ auto lrMetalinkHash = static_cast<const LrMetalinkHash *>(hash->data);
+ for (auto algorithm : RECOGNIZED_CHKSUMS) {
+ if (strcmp(lrMetalinkHash->type, algorithm) == 0)
+ hashes.push_back({lrMetalinkHash, {nullptr, chksumFree}});
+ }
+ }
+ if (hashes.empty()) {
+ logger->debug(tfm::format(_("reviving: repo '%s' skipped, no usable hash."), id));
+ return false;
+ }
+
+ for (auto & hash : hashes) {
+ auto chkType = solv_chksum_str2type(hash.lrMetalinkHash->type);
+ hash.chksum.reset(solv_chksum_create(chkType));
+ }
+
+ std::ifstream repomd(repomdFn, std::ifstream::binary);
+ char buf[4096];
+ int readed;
+ while ((readed = repomd.readsome(buf, sizeof(buf))) > 0) {
+ for (auto & hash : hashes)
+ solv_chksum_add(hash.chksum.get(), buf, readed);
+ }
+
+ for (auto & hash : hashes) {
+ int chksumLen;
+ auto chksum = solv_chksum_get(hash.chksum.get(), &chksumLen);
+ char chksumHex[chksumLen * 2 + 1];
+ solv_bin2hex(chksum, chksumLen, chksumHex);
+ if (strcmp(chksumHex, hash.lrMetalinkHash->value) != 0) {
+ logger->debug(tfm::format(_("reviving: failed for '%s', mismatched %s sum."),
+ id, hash.lrMetalinkHash->type));
+ return false;
+ }
+ }
+
+ logger->debug(tfm::format(_("reviving: '%s' can be revived - metalink checksums match."), id));
+ return true;
+}
+
+// Use repomd to check whether our metadata are still current.
+bool Repo::Impl::isRepomdInSync()
+{
+ auto logger(Log::getLogger());
+ LrYumRepo *yum_repo;
+ char tmpdir[] = "/tmp/tmpdir.XXXXXX";
+ if (!mkdtemp(tmpdir)) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"),
+ tmpdir, errTxt));
+ }
+ Finalizer tmpDirRemover([&tmpdir](){
+ dnf_remove_recursive(tmpdir, NULL);
+ });
+
+ const char *dlist[] = LR_YUM_REPOMDONLY;
+
+ std::unique_ptr<LrHandle> h(lrHandleInitRemote(tmpdir));
+
+ handleSetOpt(h.get(), LRO_YUMDLIST, dlist);
+ auto r = lrHandlePerform(h.get(), tmpdir, conf->repo_gpgcheck().getValue());
+ resultGetInfo(r.get(), LRR_YUM_REPO, &yum_repo);
+
+ auto same = haveFilesSameContent(repomdFn.c_str(), yum_repo->repomd);
+ if (same)
+ logger->debug(tfm::format(_("reviving: '%s' can be revived - repomd matches."), id));
+ else
+ logger->debug(tfm::format(_("reviving: failed for '%s', mismatched repomd."), id));
+ return same;
+}
+
+bool Repo::Impl::isInSync()
+{
+ if (!conf->metalink().empty() && !conf->metalink().getValue().empty())
+ return isMetalinkInSync();
+ return isRepomdInSync();
+}
+
+
+
+void Repo::Impl::fetch(const std::string & destdir, std::unique_ptr<LrHandle> && h)
+{
+ auto repodir = destdir + "/" + METADATA_RELATIVE_DIR;
+ if (g_mkdir_with_parents(destdir.c_str(), 0755) == -1) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create repo destination directory \"%s\": %s"),
+ destdir, errTxt));
+ }
+ auto tmpdir = destdir + "/tmpdir.XXXXXX";
+ if (!mkdtemp(&tmpdir.front())) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"),
+ tmpdir.c_str(), errTxt));
+ }
+ Finalizer tmpDirRemover([&tmpdir](){
+ dnf_remove_recursive(tmpdir.c_str(), NULL);
+ });
+ auto tmprepodir = tmpdir + "/" + METADATA_RELATIVE_DIR;
+
+ handleSetOpt(h.get(), LRO_DESTDIR, tmpdir.c_str());
+ auto r = lrHandlePerform(h.get(), tmpdir, conf->repo_gpgcheck().getValue());
+
+ dnf_remove_recursive(repodir.c_str(), NULL);
+ if (g_mkdir_with_parents(repodir.c_str(), 0755) == -1) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create directory \"%s\": %s"),
+ repodir, errTxt));
+ }
+ // move all downloaded object from tmpdir to destdir
+ if (auto * dir = opendir(tmpdir.c_str())) {
+ Finalizer tmpDirRemover([dir](){ closedir(dir); });
+ while (auto ent = readdir(dir)) {
+ auto elName = ent->d_name;
+ if (elName[0] == '.' && (elName[1] == '\0' || (elName[1] == '.' && elName[2] == '\0'))) {
+ continue;
+ }
+ auto targetElement = destdir + "/" + elName;
+ if (filesystem::exists(targetElement)) {
+ if (filesystem::isDIR(targetElement.c_str())) {
+ dnf_remove_recursive(targetElement.c_str(), NULL);
+ } else {
+ dnf_ensure_file_unlinked(targetElement.c_str(), NULL);
+ }
+ }
+ auto tempElement = tmpdir + "/" + elName;
+ GError * error = NULL;
+ if (!dnf_move_recursive(tempElement.c_str(), targetElement.c_str(), &error)) {
+ std::string errTxt = tfm::format(
+ _("Cannot rename directory \"%s\" to \"%s\": %s"),
+ tempElement, targetElement, error->message);
+ g_error_free(error);
+ throw RepoError(errTxt);
+ }
+ }
+ }
+}
+
+void Repo::Impl::downloadMetadata(const std::string & destdir)
+{
+ std::unique_ptr<LrHandle> h(lrHandleInitRemote(nullptr));
+ handleSetOpt(h.get(), LRO_YUMDLIST, LR_RPMMD_FULL);
+ fetch(destdir, std::move(h));
+}
+
+bool Repo::Impl::load()
+{
+ auto logger(Log::getLogger());
+ try {
+ if (!getMetadataPath(MD_TYPE_PRIMARY).empty() || loadCache(false)) {
+ resetMetadataExpired();
+ if (!expired || syncStrategy == SyncStrategy::ONLY_CACHE || syncStrategy == SyncStrategy::LAZY) {
+ logger->debug(tfm::format(_("repo: using cache for: %s"), id));
+ return false;
+ }
+
+ if (isInSync()) {
+ // the expired metadata still reflect the origin:
+ utimes(getMetadataPath(MD_TYPE_PRIMARY).c_str(), NULL);
+ expired = false;
+ return true;
+ }
+ }
+ if (syncStrategy == SyncStrategy::ONLY_CACHE) {
+ auto msg = tfm::format(_("Cache-only enabled but no cache for '%s'"), id);
+ throw RepoError(msg);
+ }
+
+ logger->debug(tfm::format(_("repo: downloading from remote: %s"), id));
+ const auto cacheDir = getCachedir();
+ fetch(cacheDir, lrHandleInitRemote(nullptr));
+ timestamp = -1;
+ loadCache(true);
+ fresh = true;
+ } catch (const LrExceptionWithSourceUrl & e) {
+ auto msg = tfm::format(_("Failed to download metadata for repo '%s': %s"), id, e.what());
+ throw RepoError(msg);
+ }
+ expired = false;
+ return true;
+}
+
+std::string Repo::Impl::getHash() const
+{
+ std::string tmp;
+ if (conf->metalink().empty() || (tmp=conf->metalink().getValue()).empty()) {
+ if (conf->mirrorlist().empty() || (tmp=conf->mirrorlist().getValue()).empty()) {
+ if (!conf->baseurl().getValue().empty())
+ tmp = conf->baseurl().getValue()[0];
+ if (tmp.empty())
+ tmp = id;
+ }
+ }
+
+ auto chksumObj = solv_chksum_create(REPOKEY_TYPE_SHA256);
+ solv_chksum_add(chksumObj, tmp.c_str(), tmp.length());
+ int chksumLen;
+ auto chksum = solv_chksum_get(chksumObj, &chksumLen);
+ static constexpr int USE_CHECKSUM_BYTES = 8;
+ if (chksumLen < USE_CHECKSUM_BYTES) {
+ solv_chksum_free(chksumObj, nullptr);
+ throw Exception(_("getCachedir(): Computation of SHA256 failed"));
+ }
+ char chksumCStr[USE_CHECKSUM_BYTES * 2 + 1];
+ solv_bin2hex(chksum, USE_CHECKSUM_BYTES, chksumCStr);
+ solv_chksum_free(chksumObj, nullptr);
+
+ return id + "-" + chksumCStr;
+}
+
+std::string Repo::Impl::getCachedir() const
+{
+ if (conf->basecachedir().empty()) {
+ throw Exception(tfm::format(_("repo '%s': 'basecachedir' is not set"), id));
+ }
+ auto repodir(conf->basecachedir().getValue());
+ if (repodir.back() != '/')
+ repodir.push_back('/');
+ return repodir + getHash();
+}
+
+std::string Repo::Impl::getPersistdir() const
+{
+ auto persdir(conf->getMainConfig().persistdir().getValue());
+ if (persdir.back() != '/')
+ persdir.push_back('/');
+ std::string result = persdir + "repos/" + getHash();
+ if (g_mkdir_with_parents(result.c_str(), 0755) == -1) {
+ const char * errTxt = strerror(errno);
+ throw RepoError(tfm::format(_("Cannot create persistdir \"%s\": %s"),
+ result, errTxt));
+ }
+ return result;
+}
+
+/* Returns this system's installation time ("epoch") as a UNIX timestamp.
+ *
+ * Uses the machine-id(5) file's mtime as a good-enough source of truth. This
+ * file is typically tied to the system's installation or first boot where it's
+ * populated by an installer tool or init system, respectively, and is never
+ * changed afterwards.
+ *
+ * Some systems, such as containers that don't run an init system, may have the
+ * file missing, empty or uninitialized, in which case this function returns 0.
+ */
+time_t Repo::Impl::getSystemEpoch() const
+{
+ std::string filename = "/etc/machine-id";
+ std::string id;
+ struct stat st;
+
+ if (stat(filename.c_str(), &st) != 0 || !st.st_size)
+ return 0;
+ std::ifstream(filename) >> id;
+ if (id == "uninitialized")
+ return 0;
+
+ return st.st_mtime;
+}
+
+int Repo::Impl::getAge() const
+{
+ return time(NULL) - mtime(getMetadataPath(MD_TYPE_PRIMARY).c_str());
+}
+
+void Repo::Impl::expire()
+{
+ expired = true;
+ timestamp = 0;
+}
+
+bool Repo::Impl::isExpired() const
+{
+ if (expired)
+ // explicitly requested expired state
+ return true;
+ if (conf->metadata_expire().getValue() == -1)
+ return false;
+ return getAge() > conf->metadata_expire().getValue();
+}
+
+int Repo::Impl::getExpiresIn() const
+{
+ return conf->metadata_expire().getValue() - getAge();
+}
+
+void Repo::Impl::downloadUrl(const char * url, int fd)
+{
+ if (callbacks)
+ callbacks->start(
+ !conf->name().getValue().empty() ? conf->name().getValue().c_str() :
+ (!id.empty() ? id.c_str() : "unknown")
+ );
+
+ GError * errP{nullptr};
+ lr_download_url(getCachedHandle(), url, fd, &errP);
+ std::unique_ptr<GError> err(errP);
+
+ if (callbacks)
+ callbacks->end();
+
+ if (err)
+ throw LrExceptionWithSourceUrl(err->code, err->message, url);
+}
+
+void Repo::Impl::setHttpHeaders(const char * headers[])
+{
+ if (!headers) {
+ httpHeaders.reset();
+ return;
+ }
+ size_t headersCount = 0;
+ while (headers[headersCount])
+ ++headersCount;
+ httpHeaders.reset(new char*[headersCount + 1]{});
+ for (size_t i = 0; i < headersCount; ++i) {
+ httpHeaders[i] = new char[strlen(headers[i]) + 1];
+ strcpy(httpHeaders[i], headers[i]);
+ }
+}
+
+const char * const * Repo::Impl::getHttpHeaders() const
+{
+ return httpHeaders.get();
+}
+
+bool Repo::fresh()
+{
+ return pImpl->fresh;
+}
+
+void Repo::Impl::resetMetadataExpired()
+{
+ if (expired || conf->metadata_expire().getValue() == -1)
+ return;
+ if (conf->getMainConfig().check_config_file_age().getValue() &&
+ !repoFilePath.empty() &&
+ mtime(repoFilePath.c_str()) > mtime(getMetadataPath(MD_TYPE_PRIMARY).c_str()))
+ expired = true;
+ else
+ expired = getAge() > conf->metadata_expire().getValue();
+}
+
+
+/* Returns a librepo handle, set as per the repo options
+ Note that destdir is None, and the handle is cached.*/
+LrHandle * Repo::Impl::getCachedHandle()
+{
+ if (!handle)
+ handle = lrHandleInitRemote(nullptr);
+ handleSetOpt(handle.get(), LRO_HTTPHEADER, httpHeaders.get());
+ return handle.get();
+}
+
+void Repo::Impl::attachLibsolvRepo(LibsolvRepo * libsolvRepo)
+{
+ std::lock_guard<std::mutex> guard(attachLibsolvMutex);
+
+ if (this->libsolvRepo)
+ // A libsolvRepo was attached to this object before. Remove it's reference to this object.
+ this->libsolvRepo->appdata = nullptr;
+ else
+ // The libsolvRepo will reference this object. Increase reference counter.
+ ++nrefs;
+
+ libsolvRepo->appdata = owner; // The libsolvRepo references back to us.
+ libsolvRepo->subpriority = -owner->getCost();
+ libsolvRepo->priority = -owner->getPriority();
+ this->libsolvRepo = libsolvRepo;
+}
+
+void Repo::Impl::detachLibsolvRepo()
+{
+ attachLibsolvMutex.lock();
+ if (!libsolvRepo) {
+ // Nothing to do, libsolvRepo is not attached.
+ attachLibsolvMutex.unlock();
+ return;
+ }
+
+ libsolvRepo->appdata = nullptr; // Removes reference to this object from libsolvRepo.
+ this->libsolvRepo = nullptr;
+
+ if (--nrefs <= 0) {
+ // There is no reference to this object, we are going to destroy it.
+ // Mutex is part of this object, we must unlock it before destroying.
+ attachLibsolvMutex.unlock();
+ delete owner;
+ } else
+ attachLibsolvMutex.unlock();
+}
+
+LrAuth Repo::Impl::stringToProxyAuthMethods(const std::string & proxyAuthMethodStr) noexcept
+{
+ auto proxyAuthMethods = LR_AUTH_ANY;
+ for (auto & auth : PROXYAUTHMETHODS) {
+ if (proxyAuthMethodStr == auth.name) {
+ proxyAuthMethods = auth.code;
+ break;
+ }
+ }
+ return proxyAuthMethods;
+}
+
+void Repo::setMaxMirrorTries(int maxMirrorTries)
+{
+ pImpl->maxMirrorTries = maxMirrorTries;
+}
+
+int Repo::getTimestamp() const
+{
+ return pImpl->timestamp;
+}
+
+int Repo::getMaxTimestamp()
+{
+ return pImpl->maxTimestamp;
+}
+
+void Repo::setPreserveRemoteTime(bool preserveRemoteTime)
+{
+ pImpl->preserveRemoteTime = preserveRemoteTime;
+}
+
+bool Repo::getPreserveRemoteTime() const
+{
+ return pImpl->preserveRemoteTime;
+}
+
+const std::vector<std::string> & Repo::getContentTags()
+{
+ return pImpl->content_tags;
+}
+
+const std::vector<std::pair<std::string, std::string>> & Repo::getDistroTags()
+{
+ return pImpl->distro_tags;
+}
+
+const std::vector<std::pair<std::string, std::string>> Repo::getMetadataLocations() const
+{
+ return pImpl->metadata_locations;
+}
+
+const std::string & Repo::getRevision() const
+{
+ return pImpl->revision;
+}
+
+std::string Repo::getCachedir() const
+{
+ return pImpl->getCachedir();
+}
+
+void Repo::setRepoFilePath(const std::string & path)
+{
+ pImpl->repoFilePath = path;
+}
+
+const std::string & Repo::getRepoFilePath() const noexcept
+{
+ return pImpl->repoFilePath;
+}
+
+void Repo::setSyncStrategy(SyncStrategy strategy)
+{
+ pImpl->syncStrategy = strategy;
+}
+
+Repo::SyncStrategy Repo::getSyncStrategy() const noexcept
+{
+ return pImpl->syncStrategy;
+}
+
+void Repo::downloadUrl(const char * url, int fd)
+{
+ pImpl->downloadUrl(url, fd);
+}
+
+void Repo::setHttpHeaders(const char * headers[])
+{
+ pImpl->setHttpHeaders(headers);
+}
+
+const char * const * Repo::getHttpHeaders() const
+{
+ return pImpl->getHttpHeaders();
+}
+
+std::vector<std::string> Repo::getMirrors() const
+{
+ std::vector<std::string> mirrors;
+ if (pImpl->mirrors) {
+ for (auto mirror = pImpl->mirrors; *mirror; ++mirror)
+ mirrors.emplace_back(*mirror);
+ }
+ return mirrors;
+}
+
+int PackageTargetCB::end(TransferStatus status, const char * msg) { return 0; }
+int PackageTargetCB::progress(double totalToDownload, double downloaded) { return 0; }
+int PackageTargetCB::mirrorFailure(const char *msg, const char *url) { return 0; }
+
+class PackageTarget::Impl {
+public:
+ Impl(Repo * repo, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks);
+
+ Impl(ConfigMain * cfg, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const char * httpHeaders[]);
+
+ void download();
+
+ ~Impl();
+
+ PackageTargetCB * callbacks;
+
+ std::unique_ptr<LrPackageTarget> lrPkgTarget;
+
+private:
+ void init(LrHandle * handle, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd);
+
+ static int endCB(void * data, LrTransferStatus status, const char * msg);
+ static int progressCB(void * data, double totalToDownload, double downloaded);
+ static int mirrorFailureCB(void * data, const char * msg, const char * url);
+
+ std::unique_ptr<LrHandle> lrHandle;
+
+};
+
+
+int PackageTarget::Impl::endCB(void * data, LrTransferStatus status, const char * msg)
+{
+ if (!data)
+ return 0;
+ auto cbObject = static_cast<PackageTargetCB *>(data);
+ return cbObject->end(static_cast<PackageTargetCB::TransferStatus>(status), msg);
+}
+
+int PackageTarget::Impl::progressCB(void * data, double totalToDownload, double downloaded)
+{
+ if (!data)
+ return 0;
+ auto cbObject = static_cast<PackageTargetCB *>(data);
+ return cbObject->progress(totalToDownload, downloaded);
+}
+
+int PackageTarget::Impl::mirrorFailureCB(void * data, const char * msg, const char * url)
+{
+ if (!data)
+ return 0;
+ auto cbObject = static_cast<PackageTargetCB *>(data);
+ return cbObject->mirrorFailure(msg, url);
+}
+
+
+static LrHandle * newHandle(ConfigMain * conf)
+{
+ LrHandle *h = lr_handle_init();
+ const char * user_agent = USER_AGENT;
+ // see dnf.repo.Repo._handle_new_remote() how to pass
+ if (conf) {
+ user_agent = conf->user_agent().getValue().c_str();
+ setHandle(h, *conf);
+ }
+ handleSetOpt(h, LRO_USERAGENT, user_agent);
+ return h;
+}
+
+PackageTarget::ChecksumType PackageTarget::checksumType(const std::string & name)
+{
+ return static_cast<ChecksumType>(lr_checksum_type(name.c_str()));
+}
+
+void PackageTarget::downloadPackages(std::vector<PackageTarget *> & targets, bool failFast)
+{
+ // Convert vector to GSList
+ GSList * list{nullptr};
+ for (auto it = targets.rbegin(); it != targets.rend(); ++it)
+ list = g_slist_prepend(list, (*it)->pImpl->lrPkgTarget.get());
+ std::unique_ptr<GSList, decltype(&g_slist_free)> listGuard(list, &g_slist_free);
+
+ LrPackageDownloadFlag flags = static_cast<LrPackageDownloadFlag>(0);
+ if (failFast)
+ flags = static_cast<LrPackageDownloadFlag>(flags | LR_PACKAGEDOWNLOAD_FAILFAST);
+
+ GError * errP{nullptr};
+ lr_download_packages(list, flags, &errP);
+ std::unique_ptr<GError> err(errP);
+
+ if (err)
+ throwException(std::move(err));
+}
+
+
+PackageTarget::Impl::~Impl() {}
+
+PackageTarget::Impl::Impl(Repo * repo, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks)
+: callbacks(callbacks)
+{
+ init(repo->pImpl->getCachedHandle(), relativeUrl, dest, chksType, chksum, expectedSize,
+ baseUrl, resume, byteRangeStart, byteRangeEnd);
+}
+
+PackageTarget::Impl::Impl(ConfigMain * cfg, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const char * httpHeaders[])
+: callbacks(callbacks)
+{
+ lrHandle.reset(newHandle(cfg));
+ handleSetOpt(lrHandle.get(), LRO_HTTPHEADER, httpHeaders);
+ handleSetOpt(lrHandle.get(), LRO_REPOTYPE, LR_YUMREPO);
+ init(lrHandle.get(), relativeUrl, dest, chksType, chksum, expectedSize, baseUrl, resume,
+ byteRangeStart, byteRangeEnd);
+}
+
+void PackageTarget::Impl::init(LrHandle * handle, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd)
+{
+ LrChecksumType lrChksType = static_cast<LrChecksumType>(chksType);
+
+ if (resume && byteRangeStart) {
+ auto msg = _("resume cannot be used simultaneously with the byterangestart param");
+ throw Exception(msg);
+ }
+
+ GError * errP{nullptr};
+
+ std::string encodedUrl = relativeUrl;
+ if (encodedUrl.find("://") == std::string::npos) {
+ encodedUrl = urlEncode(encodedUrl, "/");
+ }
+
+ lrPkgTarget.reset(lr_packagetarget_new_v3(handle, encodedUrl.c_str(), dest, lrChksType, chksum,
+ expectedSize, baseUrl, resume, progressCB, callbacks, endCB,
+ mirrorFailureCB, byteRangeStart, byteRangeEnd, &errP));
+ std::unique_ptr<GError> err(errP);
+
+ if (!lrPkgTarget) {
+ auto msg = tfm::format(_("PackageTarget initialization failed: %s"), err->message);
+ throw Exception(msg);
+ }
+}
+
+PackageTarget::PackageTarget(Repo * repo, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks)
+: pImpl(new Impl(repo, relativeUrl, dest, chksType, chksum, expectedSize, baseUrl, resume,
+ byteRangeStart, byteRangeEnd, callbacks))
+{}
+
+PackageTarget::PackageTarget(ConfigMain * cfg, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const char * httpHeaders[])
+: pImpl(new Impl(cfg, relativeUrl, dest, chksType, chksum, expectedSize, baseUrl, resume,
+ byteRangeStart, byteRangeEnd, callbacks, httpHeaders))
+{}
+
+
+PackageTarget::~PackageTarget() {}
+
+PackageTargetCB * PackageTarget::getCallbacks()
+{
+ return pImpl->callbacks;
+}
+
+const char * PackageTarget::getErr()
+{
+ return pImpl->lrPkgTarget->err;
+}
+
+void Downloader::downloadURL(ConfigMain * cfg, const char * url, int fd)
+{
+ std::unique_ptr<LrHandle> lrHandle(newHandle(cfg));
+ GError * errP{nullptr};
+ lr_download_url(lrHandle.get(), url, fd, &errP);
+ std::unique_ptr<GError> err(errP);
+
+ if (err)
+ throwException(std::move(err));
+}
+
+// ============ librepo logging ===========
+
+#define LR_LOGDOMAIN "librepo"
+
+class LrHandleLogData {
+public:
+ std::string filePath;
+ long uid;
+ FILE *fd;
+ bool used{false};
+ guint handlerId;
+
+ ~LrHandleLogData();
+};
+
+LrHandleLogData::~LrHandleLogData()
+{
+ if (used)
+ g_log_remove_handler(LR_LOGDOMAIN, handlerId);
+ fclose(fd);
+}
+
+static std::list<std::unique_ptr<LrHandleLogData>> lrLogDatas;
+static std::mutex lrLogDatasMutex;
+
+static const Logger::Level lrLogLevelFlagToLevel(GLogLevelFlags logLevelFlag)
+{
+ if (logLevelFlag & G_LOG_LEVEL_ERROR) {
+ return Logger::Level::ERROR;
+ }
+ if (logLevelFlag & G_LOG_LEVEL_CRITICAL) {
+ return Logger::Level::WARNING;
+ }
+ if (logLevelFlag & G_LOG_LEVEL_WARNING) {
+ return Logger::Level::WARNING;
+ }
+ if (logLevelFlag & G_LOG_LEVEL_MESSAGE) {
+ return Logger::Level::NOTICE;
+ }
+ if (logLevelFlag & G_LOG_LEVEL_INFO) {
+ return Logger::Level::INFO;
+ }
+ if (logLevelFlag & G_LOG_LEVEL_DEBUG) {
+ return Logger::Level::DEBUG;
+ }
+ return Logger::Level::TRACE;
+}
+
+static void librepoLogCB(G_GNUC_UNUSED const gchar *log_domain, GLogLevelFlags log_level,
+ const char *msg, gpointer user_data) noexcept
+{
+ auto logger(Log::getLogger());
+ logger->write(Logger::LOG_SOURCE_LIBREPO, lrLogLevelFlagToLevel(log_level), msg);
+}
+
+long LibrepoLog::addHandler(const std::string & filePath, bool debug)
+{
+ static long uid = 0;
+
+ // Open the file
+ FILE *fd = fopen(filePath.c_str(), "a");
+ if (!fd)
+ throw RepoError(tfm::format(_("Cannot open %s: %s"), filePath, g_strerror(errno)));
+
+ // Setup user data
+ std::unique_ptr<LrHandleLogData> data(new LrHandleLogData);
+ data->filePath = filePath;
+ data->fd = fd;
+
+ // Set handler
+ GLogLevelFlags log_mask = debug ? G_LOG_LEVEL_MASK : static_cast<GLogLevelFlags>(
+ G_LOG_LEVEL_INFO |
+ G_LOG_LEVEL_MESSAGE |
+ G_LOG_LEVEL_WARNING |
+ G_LOG_LEVEL_CRITICAL |
+ G_LOG_LEVEL_ERROR);
+
+ data->handlerId = g_log_set_handler(LR_LOGDOMAIN, log_mask, librepoLogCB, data.get());
+ data->used = true;
+
+ // Save user data (in a thread safe way)
+ {
+ std::lock_guard<std::mutex> guard(lrLogDatasMutex);
+
+ // Get unique ID of the handler
+ data->uid = ++uid;
+
+ // Append the data to the global list
+ lrLogDatas.push_front(std::move(data));
+ }
+
+ // Log librepo version and current time (including timezone)
+ lr_log_librepo_summary();
+
+ // Return unique id of the handler data
+ return uid;
+}
+
+void LibrepoLog::removeHandler(long uid)
+{
+ std::lock_guard<std::mutex> guard(lrLogDatasMutex);
+
+ // Search for the corresponding LogFileData
+ auto it = lrLogDatas.begin();
+ for (; it != lrLogDatas.end() && (*it)->uid != uid; ++it);
+ if (it == lrLogDatas.end())
+ throw Exception(tfm::format(_("Log handler with id %ld doesn't exist"), uid));
+
+ // Remove the handler and free the data
+ lrLogDatas.erase(it);
+}
+
+void LibrepoLog::removeAllHandlers()
+{
+ std::lock_guard<std::mutex> guard(lrLogDatasMutex);
+ lrLogDatas.clear();
+}
+
+Repo::Impl * repoGetImpl(Repo * repo)
+{
+ return repo->pImpl.get();
+}
+
+}
+
+// hawkey
+#include "../hy-repo-private.hpp"
+
+void
+repo_internalize_all_trigger(Pool *pool)
+{
+ int i;
+ Repo *repo;
+
+ FOR_REPOS(i, repo)
+ repo_internalize_trigger(repo);
+}
+
+void
+repo_internalize_trigger(Repo * repo)
+{
+ if (!repo)
+ return;
+
+ if (auto hrepo = static_cast<HyRepo>(repo->appdata)) {
+ // HyRepo is attached. The hint needs_internalizing will be used.
+ auto repoImpl = libdnf::repoGetImpl(hrepo);
+ assert(repoImpl->libsolvRepo == repo);
+ if (!repoImpl->needs_internalizing)
+ return;
+ repoImpl->needs_internalizing = false;
+ }
+
+ repo_internalize(repo);
+}
+
+void
+repo_update_state(HyRepo repo, enum _hy_repo_repodata which,
+ enum _hy_repo_state state)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ assert(state <= _HY_WRITTEN);
+ switch (which) {
+ case _HY_REPODATA_FILENAMES:
+ repoImpl->state_filelists = state;
+ return;
+ case _HY_REPODATA_PRESTO:
+ repoImpl->state_presto = state;
+ return;
+ case _HY_REPODATA_UPDATEINFO:
+ repoImpl->state_updateinfo = state;
+ return;
+ case _HY_REPODATA_OTHER:
+ repoImpl->state_other = state;
+ return;
+ default:
+ assert(0);
+ }
+ return;
+}
+
+Id
+repo_get_repodata(HyRepo repo, enum _hy_repo_repodata which)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ switch (which) {
+ case _HY_REPODATA_FILENAMES:
+ return repoImpl->filenames_repodata;
+ case _HY_REPODATA_PRESTO:
+ return repoImpl->presto_repodata;
+ case _HY_REPODATA_UPDATEINFO:
+ return repoImpl->updateinfo_repodata;
+ case _HY_REPODATA_OTHER:
+ return repoImpl->other_repodata;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+void
+repo_set_repodata(HyRepo repo, enum _hy_repo_repodata which, Id repodata)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ switch (which) {
+ case _HY_REPODATA_FILENAMES:
+ repoImpl->filenames_repodata = repodata;
+ return;
+ case _HY_REPODATA_PRESTO:
+ repoImpl->presto_repodata = repodata;
+ return;
+ case _HY_REPODATA_UPDATEINFO:
+ repoImpl->updateinfo_repodata = repodata;
+ return;
+ case _HY_REPODATA_OTHER:
+ repoImpl->other_repodata = repodata;
+ return;
+ default:
+ assert(0);
+ return;
+ }
+}
+
+// public functions
+
+HyRepo
+hy_repo_create(const char *name)
+{
+ assert(name);
+ auto & cfgMain = libdnf::getGlobalMainConfig();
+ std::unique_ptr<libdnf::ConfigRepo> cfgRepo(new libdnf::ConfigRepo(cfgMain));
+ auto repo = new libdnf::Repo(name, std::move(cfgRepo), libdnf::Repo::Type::COMMANDLINE);
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ repoImpl->conf->name().set(libdnf::Option::Priority::RUNTIME, name);
+ return repo;
+}
+
+int
+hy_repo_get_cost(HyRepo repo)
+{
+ return repo->getCost();
+}
+
+int
+hy_repo_get_priority(HyRepo repo)
+{
+ return repo->getPriority();
+}
+
+gboolean
+hy_repo_get_use_includes(HyRepo repo)
+{
+ return repo->getUseIncludes();
+}
+
+guint
+hy_repo_get_n_solvables(HyRepo repo)
+{
+ return (guint)libdnf::repoGetImpl(repo)->libsolvRepo->nsolvables;
+}
+
+void
+hy_repo_set_cost(HyRepo repo, int value)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ repoImpl->conf->cost().set(libdnf::Option::Priority::RUNTIME, value);
+ if (repoImpl->libsolvRepo)
+ repoImpl->libsolvRepo->subpriority = -value;
+}
+
+void
+hy_repo_set_priority(HyRepo repo, int value)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ repoImpl->conf->priority().set(libdnf::Option::Priority::RUNTIME, value);
+ if (repoImpl->libsolvRepo)
+ repoImpl->libsolvRepo->priority = -value;
+}
+
+void
+hy_repo_set_use_includes(HyRepo repo, gboolean enabled)
+{
+ repo->setUseIncludes(enabled);
+}
+
+void
+hy_repo_set_string(HyRepo repo, int which, const char *str_val)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ switch (which) {
+ case HY_REPO_NAME:
+ repoImpl->id = str_val;
+ repoImpl->conf->name().set(libdnf::Option::Priority::RUNTIME, str_val);
+ break;
+ case HY_REPO_MD_FN:
+ repoImpl->repomdFn = str_val ? str_val : "";
+ break;
+ case HY_REPO_PRIMARY_FN:
+ repoImpl->metadataPaths[MD_TYPE_PRIMARY] = str_val ? str_val : "";
+ break;
+ case HY_REPO_FILELISTS_FN:
+ repoImpl->metadataPaths[MD_TYPE_FILELISTS] = str_val ? str_val : "";
+ break;
+ case HY_REPO_PRESTO_FN:
+ repoImpl->metadataPaths[MD_TYPE_PRESTODELTA] = str_val ? str_val : "";
+ break;
+ case HY_REPO_UPDATEINFO_FN:
+ repoImpl->metadataPaths[MD_TYPE_UPDATEINFO] = str_val ? str_val : "";
+ break;
+ case HY_REPO_OTHER_FN:
+ repoImpl->metadataPaths[MD_TYPE_OTHER] = str_val ? str_val : "";
+ break;
+ case MODULES_FN:
+ repoImpl->metadataPaths[MD_TYPE_MODULES] = str_val ? str_val : "";
+ break;
+ default:
+ assert(0);
+ }
+}
+
+const char *
+hy_repo_get_string(HyRepo repo, int which)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ const char * ret;
+ switch(which) {
+ case HY_REPO_NAME:
+ return repoImpl->id.c_str();
+ case HY_REPO_MD_FN:
+ ret = repoImpl->repomdFn.c_str();
+ break;
+ case HY_REPO_PRIMARY_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_PRIMARY).c_str();
+ break;
+ case HY_REPO_FILELISTS_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_FILELISTS).c_str();
+ break;
+ case HY_REPO_PRESTO_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_PRESTODELTA).c_str();
+ break;
+ case HY_REPO_UPDATEINFO_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_UPDATEINFO).c_str();
+ break;
+ case HY_REPO_OTHER_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_OTHER).c_str();
+ break;
+ case MODULES_FN:
+ ret = repoImpl->getMetadataPath(MD_TYPE_MODULES).c_str();
+ break;
+ default:
+ return nullptr;
+ }
+ return ret[0] == '\0' ? nullptr : ret;
+}
+
+void
+hy_repo_free(HyRepo repo)
+{
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ {
+ std::lock_guard<std::mutex> guard(repoImpl->attachLibsolvMutex);
+ if (--repoImpl->nrefs > 0)
+ return; // There is still a reference to this object. Don't destroy it.
+ }
+ assert(!repoImpl->libsolvRepo);
+ delete repo;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_REPO_HPP
+#define _LIBDNF_REPO_HPP
+
+#define MODULEMD
+
+#include "../conf/ConfigRepo.hpp"
+#include "../error.hpp"
+#include "../hy-types.h"
+
+#include <memory>
+#include <stdexcept>
+
+namespace libdnf {
+
+class LrException : public std::runtime_error {
+public:
+ LrException(int code, const char * msg) : runtime_error(msg), code(code) {}
+ LrException(int code, const std::string & msg) : runtime_error(msg), code(code) {}
+ int getCode() const noexcept { return code; }
+private:
+ int code;
+};
+
+/**
+* @class RepoCB
+*
+* @brief Base class for Repo callbacks
+*
+* User implements repo callbacks by inheriting this class and overriding its methods.
+*/
+class RepoCB {
+public:
+ enum class FastestMirrorStage {
+ INIT, /*!<
+ Fastest mirror detection just started.
+ ptr is NULL*/
+
+ CACHELOADING, /*!<
+ ptr is (char *) pointer to string with path to the cache file.
+ (Do not modify or free the string). */
+
+ CACHELOADINGSTATUS, /*!<
+ if cache was loaded successfully, ptr is NULL, otherwise
+ ptr is (char *) string with error message.
+ (Do not modify or free the string) */
+
+ DETECTION, /*!<
+ Detection (pinging) in progress.
+ If all data was loaded from cache, this stage is skiped.
+ ptr is pointer to long. This is the number of how much
+ mirrors have to be "pinged" */
+
+ FINISHING, /*!<
+ Detection is done, sorting mirrors, updating cache, etc.
+ ptr is NULL */
+
+ STATUS, /*!<
+ The very last invocation of fastest mirror callback.
+ If fastest mirror detection was successful ptr is NULL,
+ otherwise ptr contain (char *) string with error message.
+ (Do not modify or free the string) */
+ };
+
+ virtual void start(const char *what) {}
+ virtual void end() {}
+ virtual int progress(double totalToDownload, double downloaded);
+ virtual void fastestMirror(FastestMirrorStage stage, const char *msg);
+ virtual int handleMirrorFailure(const char *msg, const char *url, const char *metadata);
+ virtual bool repokeyImport(const std::string & id, const std::string & userId,
+ const std::string & fingerprint, const std::string & url, long int timestamp);
+ virtual ~RepoCB() = default;
+};
+
+/**
+* @class Repo
+*
+* @brief Package repository
+*
+* Represents a repository used to download packages.
+* Remote metadata is cached locally.
+*
+*/
+struct Repo {
+public:
+
+ enum class Type {
+ AVAILABLE,
+ SYSTEM,
+ COMMANDLINE
+ };
+
+ enum class SyncStrategy {
+ // use the local cache even if it's expired. download if there's no cache.
+ LAZY = 1,
+ // use the local cache, even if it's expired, never download.
+ ONLY_CACHE = 2,
+ // try the cache, if it is expired download new md.
+ TRY_CACHE = 3
+ };
+
+
+ /**
+ * @brief Verify repo ID
+ *
+ * @param id repo ID to verify
+ * @return index of the first invalid character in the repo ID (if present) or -1
+ */
+ static int verifyId(const std::string & id);
+
+ /**
+ * @brief Construct the Repo object
+ *
+ * @param id repo ID to use
+ * @param conf configuration to use
+ */
+ Repo(const std::string & id, std::unique_ptr<ConfigRepo> && conf, Repo::Type type = Repo::Type::AVAILABLE);
+
+ Repo & operator =(Repo && repo) = delete;
+
+ void setCallbacks(std::unique_ptr<RepoCB> && callbacks);
+
+ /**
+ * @brief Verify repo object configuration
+ *
+ * Will throw exception if Repo has no mirror or baseurl set or if Repo type is unsupported.
+ */
+ void verify() const;
+ ConfigRepo * getConfig() noexcept;
+ const std::string & getId() const noexcept;
+ void enable();
+ void disable();
+ bool isEnabled() const;
+ bool isLocal() const;
+ /**
+ * @brief if the repository is local, returns the baseurl in form of a
+ * local filesystem path ("file://" is stripped from it and the URL is
+ * decoded).
+ *
+ * @return A local filesystem path
+ */
+ std::string getLocalBaseurl() const;
+ /**
+ * @brief Initialize the repo with metadata
+ *
+ * Fetches new metadata from the origin or just reuses local cache if still valid.
+ *
+ * @return true if fresh metadata were downloaded, false otherwise.
+ */
+ bool load();
+ bool loadCache(bool throwExcept, bool ignoreMissing=false);
+ void downloadMetadata(const std::string & destdir);
+ bool getUseIncludes() const;
+ void setUseIncludes(bool enabled);
+ bool getLoadMetadataOther() const;
+ void setLoadMetadataOther(bool value);
+ int getCost() const;
+ int getPriority() const;
+ std::string getCompsFn(); // this is temporarily made public for DNF compatibility
+#ifdef MODULEMD
+ std::string getModulesFn(); // temporary made public
+#endif
+ const std::string & getRevision() const;
+ int getAge() const;
+
+ /**
+ * @brief Ask for additional repository metadata type to download
+ *
+ * given metadata are appended to the default metadata set when repository is downloaded
+ *
+ * @param metadataType metadata type (filelists, other, productid...)
+ */
+ void addMetadataTypeToDownload(const std::string &metadataType);
+
+ /**
+ * @brief Stop asking for this additional repository metadata type
+ *
+ * given metadata_type is no longer downloaded by default
+ * when this repository is downloaded.
+ *
+ * @param metadataType metadata type (filelists, other, productid...)
+ */
+ void removeMetadataTypeFromDownload(const std::string &metadataType);
+
+ /**
+ * @brief Return path to the particular downloaded repository metadata in cache
+ *
+ * @param metadataType metadata type (filelists, other, productid...)
+ *
+ * @return file path or empty string in case the requested metadata does not exist
+ */
+ std::string getMetadataPath(const std::string &metadataType);
+
+ /**
+ * @brief Return content of the particular downloaded repository metadata
+ *
+ * Content of compressed metadata file is returned uncompressed
+ *
+ * @param metadataType metadata type (filelists, other, productid...)
+ *
+ * @return content of metadata file or empty string in case the requested metadata does not exist
+ */
+ std::string getMetadataContent(const std::string &metadataType);
+
+ /**
+ * @brief Mark whatever is in the current cache expired.
+ *
+ * This repo instance will alway try to fetch a fresh metadata after this
+ * method is called.
+ */
+ void expire();
+
+ /**
+ * @brief Return whether the cached metadata is expired.
+ *
+ * @return bool
+ */
+ bool isExpired() const;
+
+ /**
+ * @brief Get the number of seconds after which the cached metadata will expire.
+ *
+ * Negative number means the metadata has expired already.
+ *
+ * @return Seconds to expiration
+ */
+ int getExpiresIn() const;
+
+ /**
+ * @brief Returns whether the metadata was loaded from the origin, not from cache
+ *
+ * @return bool
+ */
+ bool fresh();
+
+ void setMaxMirrorTries(int maxMirrorTries);
+ int getTimestamp() const;
+ int getMaxTimestamp();
+
+ /**
+ * @brief Try to preserve remote side timestamps
+ *
+ * When set to true the underlying librepo is asked to make an attempt to set the timestamps
+ * of the local downloaded files (repository metadata and packages) to match those from
+ * the remote files.
+ * This feature is by default switched off.
+ *
+ * @param preserveRemoteTime true - use remote file timestamp, false - use the current time
+ */
+ void setPreserveRemoteTime(bool preserveRemoteTime);
+ bool getPreserveRemoteTime() const;
+
+ const std::vector<std::string> & getContentTags();
+ const std::vector<std::pair<std::string, std::string>> & getDistroTags();
+
+ /**
+ * @brief Get list of relative locations of metadata files inside the repo
+ *
+ * e.g. [('primary', 'repodata/primary.xml.gz'), ('filelists', 'repodata/filelists.xml.gz')...]
+ *
+ * @return vector of (metadata_type, location) string pairs
+ */
+ const std::vector<std::pair<std::string, std::string>> getMetadataLocations() const;
+
+ std::string getCachedir() const;
+ void setRepoFilePath(const std::string & path);
+ const std::string & getRepoFilePath() const noexcept;
+ void setSyncStrategy(SyncStrategy strategy);
+ SyncStrategy getSyncStrategy() const noexcept;
+ void downloadUrl(const char * url, int fd);
+
+ /**
+ * @brief Set http headers.
+ *
+ * Example:
+ * {"User-Agent: Agent007", "MyMagicHeader: I'm here", nullptr}
+ *
+ * @param headers nullptr terminated array of C strings
+ */
+ void setHttpHeaders(const char * headers[]);
+
+ /**
+ * @brief Get array of added/changed/removed http headers.
+ *
+ * @return nullptr terminated array of C strings
+ */
+ const char * const * getHttpHeaders() const;
+ std::vector<std::string> getMirrors() const;
+
+ void setSubstitutions(const std::map<std::string, std::string> & substitutions);
+
+ ~Repo();
+
+ class Impl;
+private:
+ friend struct PackageTarget;
+ friend Impl * repoGetImpl(Repo * repo);
+ std::unique_ptr<Impl> pImpl;
+};
+
+struct Downloader {
+public:
+ static void downloadURL(ConfigMain * cfg, const char * url, int fd);
+};
+
+/**
+* @class PackageTargetCB
+*
+* @brief Base class for PackageTarget callbacks
+*
+* User implements PackageTarget callbacks by inheriting this class and overriding its methods.
+*/
+class PackageTargetCB {
+public:
+ /** Transfer status codes */
+ enum class TransferStatus {
+ SUCCESSFUL,
+ ALREADYEXISTS,
+ ERROR
+ };
+
+ virtual int end(TransferStatus status, const char * msg);
+ virtual int progress(double totalToDownload, double downloaded);
+ virtual int mirrorFailure(const char *msg, const char *url);
+ virtual ~PackageTargetCB() = default;
+};
+
+/**
+* @class PackageTarget
+*
+* @brief Wraps librepo PackageTarget
+*/
+struct PackageTarget {
+public:
+ /** Enum of supported checksum types.
+ * NOTE! This enum guarantee to be sorted by "hash quality"
+ */
+ enum class ChecksumType {
+ UNKNOWN,
+ MD5, /* The most weakest hash */
+ SHA1, /* | */
+ SHA224, /* | */
+ SHA256, /* | */
+ SHA384, /* \|/ */
+ SHA512, /* The most secure hash */
+ };
+
+ static ChecksumType checksumType(const std::string & name);
+ static void downloadPackages(std::vector<PackageTarget *> & targets, bool failFast);
+
+ PackageTarget(Repo * repo, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks);
+ PackageTarget(ConfigMain * cfg, const char * relativeUrl, const char * dest, int chksType,
+ const char * chksum, int64_t expectedSize, const char * baseUrl, bool resume,
+ int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
+ const char * httpHeaders[] = nullptr);
+ ~PackageTarget();
+
+ PackageTargetCB * getCallbacks();
+ const char * getErr();
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+struct LibrepoLog {
+public:
+ static long addHandler(const std::string & filePath, bool debug = false);
+ static void removeHandler(long uid);
+ static void removeAllHandlers();
+};
+
+class RepoError : public Error {
+public:
+ RepoError(const std::string & what) : Error(what) {}
+};
+
+}
+
+#endif
--- /dev/null
+set(REPO_SOURCES
+ ${REPO_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Package.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Dependency.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencyContainer.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdexcept>
+#include "Dependency.hpp"
+#include "libdnf/utils/utils.hpp"
+#include "libdnf/repo/DependencySplitter.hpp"
+
+/* workaround, libsolv lacks 'extern "C"' in its header file */
+extern "C" {
+#include <solv/pool_parserpmrichdep.h>
+#include <solv/util.h>
+}
+
+#include <stdexcept>
+
+namespace libdnf {
+
+static int transformToLibsolvComparisonType(int cmp_type)
+{
+ int type = 0;
+ if (cmp_type & HY_EQ)
+ type |= REL_EQ;
+ if (cmp_type & HY_LT)
+ type |= REL_LT;
+ if (cmp_type & HY_GT)
+ type |= REL_GT;
+
+ return type;
+}
+
+Dependency::Dependency(DnfSack *sack, Id id)
+ : sack(sack)
+ , id(id)
+{}
+
+Dependency::Dependency(DnfSack *sack, const char *name, const char *version, int cmpType)
+ : sack(sack)
+{
+ id = getReldepId(sack, name, version, cmpType);
+}
+
+Dependency::Dependency(DnfSack *sack, const std::string &dependency)
+ : sack(sack)
+{
+ id = getReldepId(sack, dependency.c_str());
+}
+
+
+Dependency::Dependency(const Dependency &dependency)
+ : sack(dependency.sack)
+ , id(dependency.id)
+{}
+
+Dependency::~Dependency() = default;
+const char *Dependency::getName() const { return pool_id2str(dnf_sack_get_pool(sack), id); }
+const char *Dependency::getRelation() const { return pool_id2rel(dnf_sack_get_pool(sack), id); }
+const char *Dependency::getVersion() const { return pool_id2evr(dnf_sack_get_pool(sack), id); }
+const char *Dependency::toString() const { return pool_dep2str(dnf_sack_get_pool(sack), id); }
+
+Id
+Dependency::getReldepId(DnfSack *sack, const char *name, const char *version, int cmpType)
+{
+ Id id;
+ int solvComparisonOperator = transformToLibsolvComparisonType(cmpType);
+ Pool *pool = dnf_sack_get_pool(sack);
+ id = pool_str2id(pool, name, 1);
+
+ if (version) {
+ Id evrId = pool_str2id(pool, version, 1);
+ id = pool_rel2id(pool, id, evrId, solvComparisonOperator, 1);
+ }
+ return id;
+}
+
+Id
+Dependency::getReldepId(DnfSack *sack, const char * reldepStr)
+{
+ if (reldepStr[0] == '(') {
+ /* Rich dependency */
+ Pool *pool = dnf_sack_get_pool (sack);
+ Id id = pool_parserpmrichdep(pool, reldepStr);
+ if (!id)
+ throw std::runtime_error("Cannot parse a dependency string");
+ return id;
+ } else {
+ DependencySplitter depSplitter;
+ if(!depSplitter.parse(reldepStr))
+ throw std::runtime_error("Cannot parse a dependency string");
+ return getReldepId(sack, depSplitter.getNameCStr(), depSplitter.getEVRCStr(),
+ depSplitter.getCmpType());
+ }
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_DEPENDENCY_HPP
+#define LIBDNF_DEPENDENCY_HPP
+
+#include <memory>
+#include <string>
+#include <vector>
+#include <solv/knownid.h>
+
+#include "libdnf/dnf-sack.h"
+
+namespace libdnf {
+
+struct Dependency
+{
+public:
+ /**
+ * @brief Creates a reldep from Id
+ */
+ Dependency(DnfSack *sack, Id id);
+
+ /**
+ * @brief Creates a reldep from name, version, and comparison type.
+ *
+ * @param sack p_sack: DnfSack*
+ * @param name p_name: Required
+ * @param version p_version: Can be also NULL
+ * @param cmpType p_cmpType: Can be 0 or HY_EQ, HY_LT, HY_GT, and their combinations
+ */
+ Dependency(DnfSack *sack, const char *name, const char *version, int cmpType);
+
+ /**
+ * @brief Creates a reldep from Char*. If parsing fails it raises std::runtime_error.
+ *
+ * @param sack p_sack:...
+ * @param dependency p_dependency:...
+ */
+ Dependency(DnfSack *sack, const std::string &dependency);
+ Dependency(const Dependency &dependency);
+ ~Dependency();
+
+ const char *getName() const;
+ const char *getRelation() const;
+ const char *getVersion() const;
+ const char *toString() const;
+ Id getId() const noexcept;
+ DnfSack * getSack() const noexcept;
+
+private:
+ friend DependencyContainer;
+
+ /**
+ * @brief Returns Id of reldep
+ *
+ * @param sack p_sack: DnfSack*
+ * @param name p_name: Required
+ * @param version p_version: Can be also NULL
+ * @param cmpType p_cmpType: Can be 0 or HY_EQ, HY_LT, HY_GT, and their combinations
+ * @return Id
+ */
+ static Id getReldepId(DnfSack *sack, const char *name, const char *version, int cmpType);
+
+ /**
+ * @brief Returns Id of reldep or raises std::runtime_error if parsing fails
+ *
+ * @param sack p_sack:DnfSack
+ * @param reldepStr p_reldepStr: const Char* of reldep
+ * @return Id
+ */
+ static Id getReldepId(DnfSack *sack, const char * reldepStr);
+
+ DnfSack *sack;
+ Id id;
+};
+
+inline Id Dependency::getId() const noexcept { return id; }
+inline DnfSack * Dependency::getSack() const noexcept { return sack; }
+
+}
+
+#endif //LIBDNF_DEPENDENCY_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+// libsolv
+extern "C" {
+#include <solv/dataiterator.h>
+}
+
+#include "DependencyContainer.hpp"
+#include "Dependency.hpp"
+#include "../DependencySplitter.hpp"
+
+namespace libdnf {
+
+DependencyContainer::DependencyContainer(const DependencyContainer &src)
+ : sack(src.sack)
+{
+ queue_init_clone(&queue, &src.queue);
+}
+
+DependencyContainer::DependencyContainer(DependencyContainer &&src)
+ : sack(src.sack)
+{
+ queue_init(&queue);
+ std::swap(queue, src.queue);
+}
+
+DependencyContainer::DependencyContainer(DnfSack *sack)
+ : sack(sack)
+{
+ queue_init(&queue);
+}
+
+DependencyContainer::DependencyContainer(DnfSack *sack, const Queue &queue)
+ : sack(sack)
+{
+ queue_init_clone(&this->queue, &queue);
+}
+
+DependencyContainer::DependencyContainer(DnfSack *sack, Queue &&queue)
+ : sack(sack), queue(queue)
+{}
+
+DependencyContainer::~DependencyContainer()
+{
+ queue_free(&queue);
+}
+
+DependencyContainer &DependencyContainer::operator=(const DependencyContainer &src)
+{
+ if (this != &src) {
+ sack = src.sack;
+ queue_free(&queue);
+ queue_init_clone(&queue, &src.queue);
+ }
+ return *this;
+}
+
+DependencyContainer &DependencyContainer::operator=(DependencyContainer &&src) noexcept
+{
+ if (this != &src) {
+ sack = src.sack;
+ std::swap(queue, src.queue);
+ }
+ return *this;
+}
+
+bool DependencyContainer::operator!=(const DependencyContainer &r) const { return !(*this == r); }
+bool DependencyContainer::operator==(const DependencyContainer &r) const
+{
+ if (queue.count != r.queue.count)
+ return false;
+
+ for (int i = 0; i < queue.count; i++) {
+ if (queue.elements[i] != r.queue.elements[i]) {
+ return false;
+ }
+ }
+
+ return dnf_sack_get_pool(sack) == dnf_sack_get_pool(r.sack);
+}
+
+void DependencyContainer::add(Dependency *dependency)
+{
+ queue_push(&queue, dependency->getId());
+}
+
+void DependencyContainer::add(Id id)
+{
+ queue_push(&queue, id);
+}
+
+bool DependencyContainer::addReldepWithGlob(const char *reldepStr)
+{
+ DependencySplitter depSplitter;
+ if(!depSplitter.parse(reldepStr))
+ return false;
+ Dataiterator di;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dataiterator_init(&di, pool, 0, 0, 0, depSplitter.getNameCStr(),
+ SEARCH_STRING | SEARCH_GLOB);
+ while (dataiterator_step(&di)) {
+ Id id = Dependency::getReldepId(sack, di.kv.str, depSplitter.getEVRCStr(),
+ depSplitter.getCmpType());
+ add(id);
+ }
+ dataiterator_free(&di);
+ return true;
+}
+
+bool DependencyContainer::addReldep(const char *reldepStr)
+{
+ try {
+ Id id = Dependency::getReldepId(sack, reldepStr);
+ add(id);
+ return true;
+ }
+ catch (...) {
+ return false;
+ }
+}
+
+void DependencyContainer::extend(DependencyContainer *container)
+{
+ queue_insertn(&queue, 0, container->queue.count, container->queue.elements);
+}
+
+std::unique_ptr<Dependency> DependencyContainer::get(int index) const noexcept
+{
+ Id id = queue.elements[index];
+ return std::unique_ptr<Dependency> (new Dependency(sack, id));
+}
+
+Dependency *DependencyContainer::getPtr(int index) const noexcept
+{
+ Id id = queue.elements[index];
+ return new Dependency(sack, id);
+}
+
+int DependencyContainer::count() const noexcept { return queue.count; }
+const Queue &DependencyContainer::getQueue() const noexcept { return queue; }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_DEPENDENCYCONTAINER_HPP
+#define LIBDNF_DEPENDENCYCONTAINER_HPP
+
+
+#include <solv/queue.h>
+#include <memory>
+#include "libdnf/dnf-sack.h"
+
+namespace libdnf {
+
+struct Dependency;
+
+struct DependencyContainer
+{
+public:
+ DependencyContainer(const DependencyContainer &src);
+ DependencyContainer(DependencyContainer &&src);
+ explicit DependencyContainer(DnfSack *sack);
+ DependencyContainer(DnfSack *sack, const Queue &queue);
+ DependencyContainer(DnfSack *sack, Queue &&queue);
+ ~DependencyContainer();
+
+ DependencyContainer &operator=(const DependencyContainer &src);
+ DependencyContainer &operator=(DependencyContainer &&src) noexcept;
+ bool operator==(const DependencyContainer &r) const;
+ bool operator!=(const DependencyContainer &r) const;
+
+ void add(Dependency *dependency);
+ void add(Id id);
+
+ /**
+ * @brief Adds a reldep from Char*. Only globs in name are proccessed. The proccess is slow
+ * therefore if reldepStr is not a glob please use addReldep() instead.
+ *
+ * @param reldepStr p_reldepStr: Char*
+ * @return bool - false if parsing or reldep creation fails
+ */
+ bool addReldepWithGlob(const char *reldepStr);
+
+ /**
+ * @brief Adds a reldep from Char*. It does not support globs.
+ *
+ * @param reldepStr p_reldepStr: Char*
+ * @return bool false if parsing or reldep creation fails
+ */
+ bool addReldep(const char *reldepStr);
+ void extend(DependencyContainer *container);
+
+ std::unique_ptr<Dependency> get(int index) const noexcept;
+ Dependency *getPtr(int index) const noexcept;
+ Id getId(int index) const noexcept;
+ int count() const noexcept;
+
+ const Queue &getQueue() const noexcept;
+
+private:
+ DnfSack *sack;
+ Queue queue;
+};
+
+inline Id DependencyContainer::getId(int index) const noexcept
+{
+ return queue.elements[index];
+}
+
+}
+
+#endif //LIBDNF_DEPENDENCYCONTAINER_HPP
--- /dev/null
+#include "Package.hpp"
+
+#include <utility>
+#include "DependencyContainer.hpp"
+#include "libdnf/repo/Repo-private.hpp"
+
+namespace libdnf {
+
+Package::Package(DnfSack *sack, Id id)
+ : sack(sack)
+ , id(id)
+{}
+
+Package::Package(DnfSack *sack,
+ HyRepo repo,
+ const char *name,
+ const char *version,
+ const char *arch,
+ bool createSolvable)
+ : sack(sack)
+{
+ if (createSolvable) {
+ this->createSolvable(repo);
+ fillSolvableData(name, version, arch);
+ } else
+ id = 0;
+}
+
+Package::Package(DnfSack *sack,
+ HyRepo repo,
+ const std::string &name,
+ const std::string &version,
+ const std::string &arch,
+ bool createSolvable)
+ : sack(sack)
+{
+ if (createSolvable) {
+ this->createSolvable(repo);
+ fillSolvableData(name.c_str(), version.c_str(), arch.c_str());
+ } else
+ id = 0;
+}
+
+Package::Package(const Package &package)
+ : sack(package.sack)
+ , id(package.id)
+{}
+
+Package::~Package() = default;
+
+const char *Package::getSolvableName() const
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return pool_id2str(pool, solvable->name);
+}
+
+const char *Package::getSolvableEvr() const
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return pool_id2str(pool, solvable->evr);
+}
+
+const char *Package::getArch() const
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return pool_id2str(pool, solvable->arch);
+}
+
+const char *Package::getSolvableVendor() const
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solvable *solvable = pool_id2solvable(pool, id);
+ return pool_id2str(pool, solvable->vendor);
+}
+
+void Package::setSolvableVendor(const char *vendor)
+{
+ Solvable *solvable = pool_id2solvable(dnf_sack_get_pool(sack), id);
+ solvable_set_str(solvable, SOLVABLE_VENDOR, vendor);
+}
+
+Id Package::getId() const
+{
+ return id;
+}
+
+std::shared_ptr<DependencyContainer> Package::getConflicts() const
+{
+ return getDependencies(SOLVABLE_CONFLICTS);
+};
+
+std::shared_ptr<DependencyContainer> Package::getEnhances() const
+{
+ return getDependencies(SOLVABLE_ENHANCES);
+}
+
+std::shared_ptr<DependencyContainer> Package::getObsoletes() const
+{
+ return getDependencies(SOLVABLE_OBSOLETES);
+}
+
+std::shared_ptr<DependencyContainer> Package::getProvides() const
+{
+ return getDependencies(SOLVABLE_PROVIDES);
+}
+
+std::shared_ptr<DependencyContainer> Package::getRecommends() const
+{
+ return getDependencies(SOLVABLE_RECOMMENDS);
+}
+
+std::shared_ptr<DependencyContainer> Package::getRequires() const
+{
+ return getDependencies(SOLVABLE_REQUIRES, 0);
+}
+
+std::shared_ptr<DependencyContainer> Package::getRequiresPre() const
+{
+ return getDependencies(SOLVABLE_REQUIRES, 1);
+}
+
+std::shared_ptr<DependencyContainer> Package::getSuggests() const
+{
+ return getDependencies(SOLVABLE_SUGGESTS);
+}
+
+std::shared_ptr<DependencyContainer> Package::getSupplements() const
+{
+ return getDependencies(SOLVABLE_SUPPLEMENTS);
+}
+
+void Package::addConflicts(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_CONFLICTS);
+}
+
+void Package::addEnhances(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_ENHANCES);
+}
+
+void Package::addObsoletes(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_OBSOLETES);
+}
+
+void Package::addProvides(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_PROVIDES);
+}
+
+void Package::addRecommends(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_RECOMMENDS);
+}
+
+void Package::addRequires(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_REQUIRES, 0);
+}
+
+void Package::addRequiresPre(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_REQUIRES, 1);
+}
+
+void Package::addSuggests(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_SUGGESTS);
+}
+
+void Package::addSupplements(std::shared_ptr<Dependency> dependency)
+{
+ addDependency(std::move(dependency), SOLVABLE_SUPPLEMENTS);
+}
+
+void Package::createSolvable(HyRepo repo)
+{
+ id = repo_add_solvable(libdnf::repoGetImpl(repo)->libsolvRepo);
+}
+
+void Package::fillSolvableData(const char *name, const char *version,
+ const char *arch) const
+{
+ Solvable *solvable = pool_id2solvable(dnf_sack_get_pool(sack), id);
+
+ solvable_set_str(solvable, SOLVABLE_NAME, name);
+ solvable_set_str(solvable, SOLVABLE_EVR, version);
+ solvable_set_str(solvable, SOLVABLE_ARCH, arch);
+}
+
+std::shared_ptr<DependencyContainer> Package::getDependencies(Id type, Id marker) const
+{
+ auto queue = getDependencyQueue(type, marker);
+ auto container = std::make_shared<DependencyContainer>(sack, *queue);
+
+ queue_free(queue);
+ delete queue;
+
+ return container;
+}
+
+Queue *Package::getDependencyQueue(Id type, Id marker) const
+{
+ Queue dependencyQueue{};
+ auto queue = new Queue;
+
+ queue_init(queue);
+ queue_init(&dependencyQueue);
+
+ solvable_lookup_deparray(pool_id2solvable(dnf_sack_get_pool(sack), id), type, &dependencyQueue, marker);
+
+ for (int i = 0; i < dependencyQueue.count; i++) {
+ Id id = dependencyQueue.elements[i];
+ if (id != SOLVABLE_PREREQMARKER)
+ queue_push(queue, id);
+ }
+
+ queue_free(&dependencyQueue);
+
+ return queue;
+}
+
+void Package::addDependency(std::shared_ptr<Dependency> dependency, int type, Id marker)
+{
+ Solvable *solvable = pool_id2solvable(dnf_sack_get_pool(sack), id);
+ solvable_add_deparray(solvable, type, dependency->getId(), marker);
+}
+
+}
--- /dev/null
+#ifndef LIBDNF_PACKAGE_HPP
+#define LIBDNF_PACKAGE_HPP
+
+#include <vector>
+#include <solv/solvable.h>
+#include <solv/repo.h>
+
+
+#include "libdnf/hy-types.h"
+#include "libdnf/hy-repo-private.hpp"
+
+#include "Dependency.hpp"
+
+namespace libdnf {
+
+struct Package
+{
+public:
+ Package(DnfSack *sack, Id id);
+ Package(const Package &package);
+ virtual ~Package();
+
+ std::shared_ptr<DependencyContainer> getConflicts() const;
+ std::shared_ptr<DependencyContainer> getEnhances() const;
+ std::shared_ptr<DependencyContainer> getObsoletes() const;
+ std::shared_ptr<DependencyContainer> getProvides() const;
+ std::shared_ptr<DependencyContainer> getRecommends() const;
+ std::shared_ptr<DependencyContainer> getRequires() const;
+ std::shared_ptr<DependencyContainer> getRequiresPre() const;
+ std::shared_ptr<DependencyContainer> getSuggests() const;
+ std::shared_ptr<DependencyContainer> getSupplements() const;
+ Id getId() const;
+
+ virtual const char *getName() const = 0;
+ virtual const char *getVersion() const = 0;
+ const char *getArch() const;
+
+protected:
+ Package(DnfSack *sack, HyRepo repo, const char *name, const char *version, const char *arch, bool createSolvable = true);
+ Package(DnfSack *sack, HyRepo repo, const std::string &name, const std::string &version, const std::string &arch, bool createSolvable = true);
+
+ void addConflicts(std::shared_ptr<Dependency> dependency);
+ void addEnhances(std::shared_ptr<Dependency> dependency);
+ void addObsoletes(std::shared_ptr<Dependency> dependency);
+ void addProvides(std::shared_ptr<Dependency> dependency);
+ void addRecommends(std::shared_ptr<Dependency> dependency);
+ void addRequires(std::shared_ptr<Dependency> dependency);
+ void addRequiresPre(std::shared_ptr<Dependency> dependency);
+ void addSuggests(std::shared_ptr<Dependency> dependency);
+ void addSupplements(std::shared_ptr<Dependency> dependency);
+
+ const char *getSolvableName() const;
+ const char *getSolvableEvr() const;
+ const char *getSolvableVendor() const;
+ void setSolvableVendor(const char *vendor);
+
+private:
+ void createSolvable(HyRepo repo);
+ void fillSolvableData(const char *name, const char *version, const char *arch) const;
+ std::shared_ptr<DependencyContainer> getDependencies(Id type, Id marker = -1) const;
+ void addDependency(std::shared_ptr<Dependency> dependency, int type, Id marker = -1);
+ Queue *getDependencyQueue(Id type, Id marker) const;
+
+ DnfSack *sack;
+ Id id;
+};
+
+}
+
+#endif //LIBDNF_PACKAGE_HPP
--- /dev/null
+set(SACK_SOURCES
+ ${SACK_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/advisory.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/advisorymodule.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/advisorypkg.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/advisoryref.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/packageset.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/query.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/selector.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+
+#include <solv/repo.h>
+
+#include "advisory.hpp"
+#include "advisorypkg.hpp"
+#include "advisorymodule.hpp"
+#include "advisoryref.hpp"
+#include "../dnf-advisory-private.hpp"
+#include "../dnf-advisoryref.h"
+#include "../dnf-sack-private.hpp"
+
+namespace libdnf {
+
+/**
+ * str2dnf_advisory_kind:
+ * @str: a string
+ *
+ * Returns: a #DnfAdvisoryKind, e.g. %DNF_ADVISORY_KIND_BUGFIX
+ *
+ * Since: 0.7.0
+ */
+static DnfAdvisoryKind
+str2dnf_advisory_kind(const char *str)
+{
+ if (str == NULL)
+ return DNF_ADVISORY_KIND_UNKNOWN;
+ if (!strcmp (str, "bugfix"))
+ return DNF_ADVISORY_KIND_BUGFIX;
+ if (!strcmp (str, "enhancement"))
+ return DNF_ADVISORY_KIND_ENHANCEMENT;
+ if (!strcmp (str, "security"))
+ return DNF_ADVISORY_KIND_SECURITY;
+ if (!strcmp (str, "newpackage"))
+ return DNF_ADVISORY_KIND_NEWPACKAGE;
+ return DNF_ADVISORY_KIND_UNKNOWN;
+}
+
+bool
+Advisory::matchBugOrCVE(const char* what, bool matchBug) const
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char * whatMatch = matchBug ? "bugzilla" : "cve";
+ Dataiterator di;
+ dataiterator_init(&di, pool, 0, advisory, UPDATE_REFERENCE, 0, 0);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos(&di);
+ if (strcmp(pool_lookup_str(pool, SOLVID_POS, UPDATE_REFERENCE_TYPE), whatMatch) == 0) {
+ if (strcmp(pool_lookup_str(pool, SOLVID_POS, UPDATE_REFERENCE_ID), what) == 0) {
+ dataiterator_free(&di);
+ return true;
+ }
+ }
+ }
+ dataiterator_free(&di);
+ return false;
+}
+
+Advisory::Advisory(DnfSack *sack, Id advisory) : sack(sack), advisory(advisory) {}
+
+bool
+Advisory::operator==(const Advisory & other) const
+{
+ return sack == other.sack && advisory == other.advisory;
+}
+
+const char *
+Advisory::getDescription() const
+{
+ return pool_lookup_str(dnf_sack_get_pool(sack), advisory, SOLVABLE_DESCRIPTION);
+}
+
+
+DnfAdvisoryKind
+Advisory::getKind() const
+{
+ const char *type;
+ type = pool_lookup_str(dnf_sack_get_pool(sack), advisory, SOLVABLE_PATCHCATEGORY);
+ return str2dnf_advisory_kind(type);
+}
+
+const char *
+Advisory::getName() const
+{
+ const char *name;
+
+ name = pool_lookup_str(dnf_sack_get_pool(sack), advisory, SOLVABLE_NAME);
+ size_t prefix_len = strlen(SOLVABLE_NAME_ADVISORY_PREFIX);
+ assert(strncmp(SOLVABLE_NAME_ADVISORY_PREFIX, name, prefix_len) == 0);
+ //remove the prefix
+ name += prefix_len;
+
+ return name;
+}
+
+void
+Advisory::getPackages(std::vector<AdvisoryPkg> & pkglist, bool withFilemanes) const
+{
+ Dataiterator di;
+ const char * filename = nullptr;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dataiterator_init(&di, pool, 0, advisory, UPDATE_COLLECTION, 0, 0);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos(&di);
+ Id name = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_NAME);
+ Id evr = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_EVR);
+ Id arch = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_ARCH);
+ if (withFilemanes) {
+ filename = pool_lookup_str(pool, SOLVID_POS, UPDATE_COLLECTION_FILENAME);
+ }
+ pkglist.emplace_back(sack, advisory, name, evr, arch, filename);
+ }
+ dataiterator_free(&di);
+}
+
+std::vector<AdvisoryModule> Advisory::getModules() const
+{
+ std::vector<AdvisoryModule> moduleList;
+ Dataiterator di;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dataiterator_init(&di, pool, 0, advisory, UPDATE_MODULE, 0, 0);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos(&di);
+ Id name = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_NAME);
+ Id stream = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_STREAM);
+ Id version = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_VERSION);
+ Id context = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_CONTEXT);
+ Id arch = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_ARCH);
+ moduleList.emplace_back(sack, advisory, name, stream, version, context, arch);
+ }
+ dataiterator_free(&di);
+ return moduleList;
+}
+
+void
+Advisory::getApplicablePackages(std::vector<AdvisoryPkg> & pkglist, bool withFilemanes) const
+{
+ Dataiterator di;
+ Dataiterator di_inner;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dataiterator_init(&di, pool, 0, advisory, UPDATE_COLLECTIONLIST, 0, 0);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos(&di);
+
+ bool isModuleCollectionApplicable = true;
+ dataiterator_init(&di_inner, pool, 0, SOLVID_POS, UPDATE_MODULE, 0, 0);
+ while (dataiterator_step(&di_inner)) {
+ dataiterator_setpos(&di_inner);
+ Id name = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_NAME);
+ Id stream = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_STREAM);
+ Id version = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_VERSION);
+ Id context = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_CONTEXT);
+ Id arch = pool_lookup_id(pool, SOLVID_POS, UPDATE_MODULE_ARCH);
+ AdvisoryModule moduleAdvisory(sack, advisory, name, stream, version, context, arch);
+ if (moduleAdvisory.isApplicable()) {
+ isModuleCollectionApplicable = true;
+ break;
+ } else {
+ isModuleCollectionApplicable = false;
+ }
+ }
+ dataiterator_free(&di_inner);
+
+ if (isModuleCollectionApplicable) {
+ const char * filename = nullptr;
+ dataiterator_setpos(&di);
+
+ dataiterator_init(&di_inner, pool, 0, SOLVID_POS, UPDATE_COLLECTION, 0, 0);
+ while (dataiterator_step(&di_inner)) {
+ dataiterator_setpos(&di_inner);
+ Id name = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_NAME);
+ Id evr = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_EVR);
+ Id arch = pool_lookup_id(pool, SOLVID_POS, UPDATE_COLLECTION_ARCH);
+ if (withFilemanes) {
+ filename = pool_lookup_str(pool, SOLVID_POS, UPDATE_COLLECTION_FILENAME);
+ }
+ pkglist.emplace_back(sack, advisory, name, evr, arch, filename);
+ }
+ dataiterator_free(&di_inner);
+ }
+ }
+
+ dataiterator_free(&di);
+}
+
+void
+Advisory::getReferences(std::vector<AdvisoryRef> & reflist) const
+{
+ Dataiterator di;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dataiterator_init(&di, pool, 0, advisory, UPDATE_REFERENCE, 0, 0);
+ for (int index = 0; dataiterator_step(&di); index++) {
+ reflist.emplace_back(sack, advisory, index);
+ }
+ dataiterator_free(&di);
+}
+
+const char *
+Advisory::getRights() const
+{
+ return pool_lookup_str(dnf_sack_get_pool(sack), advisory, UPDATE_RIGHTS);
+}
+
+const char *
+Advisory::getSeverity() const
+{
+ return pool_lookup_str(dnf_sack_get_pool(sack), advisory, UPDATE_SEVERITY);
+}
+
+const char *
+Advisory::getTitle() const
+{
+ return pool_lookup_str(dnf_sack_get_pool(sack), advisory, SOLVABLE_SUMMARY);
+}
+
+unsigned long long int
+Advisory::getUpdated() const
+{
+ return pool_lookup_num(dnf_sack_get_pool(sack), advisory, SOLVABLE_BUILDTIME, 0);
+}
+
+bool
+Advisory::matchBug(const char *bug) const
+{
+ return matchBugOrCVE(bug, true);
+}
+
+bool
+Advisory::matchCVE(const char *cve) const
+{
+ return matchBugOrCVE(cve, false);
+}
+
+bool
+Advisory::matchKind(const char *kind) const
+{
+ auto advisoryKind = pool_lookup_str(dnf_sack_get_pool(sack), advisory, SOLVABLE_PATCHCATEGORY);
+ return advisoryKind ? strcmp(advisoryKind, kind) == 0 : false;
+}
+
+
+bool
+Advisory::matchName(const char *name) const
+{
+ auto advisoryName = getName();
+ return advisoryName ? strcmp(advisoryName, name) == 0 : false;
+}
+
+bool
+Advisory::matchSeverity(const char *severity) const
+{
+ auto advisorySeverity = getSeverity();
+ return advisorySeverity ? strcmp(advisorySeverity, severity) == 0 : false;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __ADVISORY_HPP
+#define __ADVISORY_HPP
+
+#include <memory>
+#include <vector>
+
+#include <solv/pooltypes.h>
+#include "../dnf-advisory.h"
+#include "../dnf-types.h"
+#include "advisoryref.hpp"
+
+namespace libdnf {
+
+struct AdvisoryPkg;
+struct AdvisoryModule;
+
+struct Advisory {
+public:
+ Advisory(DnfSack *sack, Id advisory);
+ bool operator ==(const Advisory & other) const;
+ const char *getDescription() const;
+ DnfAdvisoryKind getKind() const;
+ const char *getName() const;
+ void getPackages(std::vector<AdvisoryPkg> & pkglist, bool withFilemanes = true) const;
+ std::vector<AdvisoryModule> getModules() const;
+ void getApplicablePackages(std::vector<AdvisoryPkg> & pkglist, bool withFilemanes = true) const;
+ void getReferences(std::vector<AdvisoryRef> & reflist) const;
+ const char *getRights() const;
+ const char *getSeverity() const;
+ const char *getTitle() const;
+ unsigned long long int getUpdated() const;
+ bool matchBug(const char *bug) const;
+ bool matchCVE(const char *cve) const;
+ bool matchKind(const char *kind) const;
+ bool matchName(const char *name) const;
+ bool matchSeverity(const char *severity) const;
+
+private:
+ DnfSack *sack;
+ Id advisory;
+ bool matchBugOrCVE(const char *bug, bool withBug) const;
+};
+}
+
+#endif /* __ADVISORY_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string>
+
+#include <solv/poolid.h>
+
+#include "advisory.hpp"
+#include "advisorymodule.hpp"
+#include "../dnf-sack-private.hpp"
+
+namespace libdnf {
+
+class AdvisoryModule::Impl {
+private:
+ friend AdvisoryModule;
+ DnfSack *sack;
+ Id advisory;
+ Id name;
+ Id stream;
+ Id version;
+ Id context;
+ Id arch;
+};
+
+AdvisoryModule::AdvisoryModule(DnfSack *sack, Id advisory, Id name, Id stream, Id version, Id context, Id arch) : pImpl(new Impl)
+{
+ pImpl->sack = sack;
+ pImpl->advisory = advisory;
+ pImpl->name = name;
+ pImpl->stream = stream;
+ pImpl->version = version;
+ pImpl->context = context;
+ pImpl->arch = arch;
+}
+AdvisoryModule::AdvisoryModule(const AdvisoryModule & src) : pImpl(new Impl) { *pImpl = *src.pImpl; }
+AdvisoryModule::AdvisoryModule(AdvisoryModule && src) : pImpl(new Impl) { pImpl.swap(src.pImpl); }
+AdvisoryModule::~AdvisoryModule() = default;
+
+AdvisoryModule & AdvisoryModule::operator=(const AdvisoryModule & src) { *pImpl = *src.pImpl; return *this; }
+
+AdvisoryModule &
+AdvisoryModule::operator=(AdvisoryModule && src) noexcept
+{
+ pImpl.swap(src.pImpl);
+ return *this;
+}
+
+bool
+AdvisoryModule::nsvcaEQ(AdvisoryModule & other)
+{
+ return other.pImpl->name == pImpl->name &&
+ other.pImpl->stream == pImpl->stream &&
+ other.pImpl->version == pImpl->version &&
+ other.pImpl->context == pImpl->context &&
+ other.pImpl->arch == pImpl->arch;
+}
+
+bool
+AdvisoryModule::isApplicable() const {
+ auto moduleContainer = dnf_sack_get_module_container(pImpl->sack);
+ if (!moduleContainer) {
+ return false;
+ }
+
+ for (auto & module : moduleContainer->query(getName(), getStream(), {}, getContext(), {})) {
+ if (moduleContainer->isModuleActive(module)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Advisory * AdvisoryModule::getAdvisory() const
+{
+ return new Advisory(pImpl->sack, pImpl->advisory);
+}
+
+const char *
+AdvisoryModule::getName() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->name);
+}
+
+const char *
+AdvisoryModule::getStream() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->stream);
+}
+
+const char *
+AdvisoryModule::getVersion() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->version);
+}
+
+const char *
+AdvisoryModule::getContext() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->context);
+}
+
+const char *
+AdvisoryModule::getArch() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->arch);
+}
+
+DnfSack * AdvisoryModule::getSack() { return pImpl->sack; }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __ADVISORY_MODULE_HPP
+#define __ADVISORY_MODULE_HPP
+
+#include "../dnf-types.h"
+#include "advisory.hpp"
+
+#include <memory>
+
+#include <solv/pooltypes.h>
+
+
+namespace libdnf {
+
+struct AdvisoryModule {
+public:
+ AdvisoryModule(DnfSack *sack, Id advisory, Id name, Id stream, Id version, Id context, Id arch);
+ AdvisoryModule(const AdvisoryModule & src);
+ AdvisoryModule(AdvisoryModule && src);
+ ~AdvisoryModule();
+ AdvisoryModule & operator=(const AdvisoryModule & src);
+ AdvisoryModule & operator=(AdvisoryModule && src) noexcept;
+ bool nsvcaEQ(AdvisoryModule & other);
+ bool isApplicable() const;
+ Advisory * getAdvisory() const;
+ const char * getName() const;
+ const char * getStream() const;
+ const char * getVersion() const;
+ const char * getContext() const;
+ const char * getArch() const;
+ DnfSack * getSack();
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif /* __ADVISORY_MODULE_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string>
+
+#include <solv/poolid.h>
+
+#include "advisory.hpp"
+#include "advisorypkg.hpp"
+#include "../dnf-sack-private.hpp"
+
+namespace libdnf {
+
+class AdvisoryPkg::Impl {
+private:
+ friend AdvisoryPkg;
+ DnfSack *sack;
+ Id advisory;
+ Id name;
+ Id evr;
+ Id arch;
+ const char * filename;
+};
+
+AdvisoryPkg::AdvisoryPkg(DnfSack *sack, Id advisory, Id name, Id evr, Id arch, const char * filename) : pImpl(new Impl)
+{
+ pImpl->sack = sack;
+ pImpl->advisory = advisory;
+ pImpl->name = name;
+ pImpl->evr = evr;
+ pImpl->arch = arch;
+ pImpl->filename = filename;
+}
+AdvisoryPkg::AdvisoryPkg(const AdvisoryPkg & src) : pImpl(new Impl) { *pImpl = *src.pImpl; }
+AdvisoryPkg::AdvisoryPkg(AdvisoryPkg && src) : pImpl(new Impl) { pImpl.swap(src.pImpl); }
+AdvisoryPkg::~AdvisoryPkg() = default;
+
+AdvisoryPkg & AdvisoryPkg::operator=(const AdvisoryPkg & src) { *pImpl = *src.pImpl; return *this; }
+
+AdvisoryPkg &
+AdvisoryPkg::operator=(AdvisoryPkg && src) noexcept
+{
+ pImpl.swap(src.pImpl);
+ return *this;
+}
+
+bool
+AdvisoryPkg::nevraEQ(AdvisoryPkg & other)
+{
+ return other.pImpl->name == pImpl->name &&
+ other.pImpl->evr == pImpl->evr &&
+ other.pImpl->arch == pImpl->arch;
+}
+
+bool
+AdvisoryPkg::nevraEQ(Solvable *s)
+{
+ return s->name == pImpl->name && s->evr == pImpl->evr && s->arch == pImpl->arch;
+}
+
+Advisory * AdvisoryPkg::getAdvisory() const
+{
+ return new Advisory(pImpl->sack, pImpl->advisory);
+}
+
+Id AdvisoryPkg::getName() const { return pImpl->name; }
+
+const char *
+AdvisoryPkg::getNameString() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->name);
+}
+
+Id AdvisoryPkg::getEVR() const { return pImpl->evr; }
+
+const char *
+AdvisoryPkg::getEVRString() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->evr);
+}
+
+Id AdvisoryPkg::getArch() const { return pImpl->arch; }
+
+const char *
+AdvisoryPkg::getArchString() const
+{
+ return pool_id2str(dnf_sack_get_pool(pImpl->sack), pImpl->arch);
+}
+
+const char * AdvisoryPkg::getFileName() const { return pImpl->filename; }
+DnfSack * AdvisoryPkg::getSack() { return pImpl->sack; }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __ADVISORY_PKG_HPP
+#define __ADVISORY_PKG_HPP
+
+#include <memory>
+
+#include <solv/pooltypes.h>
+#include <solv/solvable.h>
+
+#include "../dnf-types.h"
+#include "advisory.hpp"
+
+namespace libdnf {
+
+struct AdvisoryPkg {
+public:
+ AdvisoryPkg(DnfSack *sack, Id advisory, Id name, Id evr, Id arch, const char * filename);
+ AdvisoryPkg(const AdvisoryPkg & src);
+ AdvisoryPkg(AdvisoryPkg && src);
+ ~AdvisoryPkg();
+ AdvisoryPkg & operator=(const AdvisoryPkg & src);
+ AdvisoryPkg & operator=(AdvisoryPkg && src) noexcept;
+ bool nevraEQ(AdvisoryPkg & other);
+ bool nevraEQ(Solvable *s);
+ Advisory * getAdvisory() const;
+ Id getName() const;
+ const char * getNameString() const;
+ Id getEVR() const;
+ const char * getEVRString() const;
+ Id getArch() const;
+ const char * getArchString() const;
+ const char * getFileName() const;
+ DnfSack * getSack();
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif /* __ADVISORY_PKG_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <solv/pooltypes.h>
+
+#include "advisoryref.hpp"
+
+namespace libdnf {
+
+AdvisoryRef::AdvisoryRef(DnfSack *sack, Id advisory, int index)
+: sack(sack), advisory(advisory), index(index) {}
+
+bool
+AdvisoryRef::operator==(const AdvisoryRef& other) const
+{
+ return advisory == other.advisory && index == other.index;
+}
+
+int AdvisoryRef::getIndex() const { return index; }
+Id AdvisoryRef::getAdvisory() const { return advisory; }
+DnfSack * AdvisoryRef::getDnfSack() const { return sack; }
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __ADVISORY_REF_HPP
+#define __ADVISORY_REF_HPP
+
+#include <memory>
+
+#include <solv/pooltypes.h>
+
+#include "../dnf-types.h"
+
+namespace libdnf {
+
+struct AdvisoryRef {
+public:
+ AdvisoryRef(DnfSack *sack, Id advisory, int index);
+
+ bool operator ==(const AdvisoryRef & other) const;
+ Id getAdvisory() const;
+ int getIndex() const;
+ DnfSack * getDnfSack() const;
+private:
+ DnfSack *sack;
+ Id advisory;
+ int index;
+};
+
+}
+
+#endif /* __ADVISORY_REF_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __CHANGELOG_HPP
+#define __CHANGELOG_HPP
+
+#include <ctime>
+#include <string>
+
+namespace libdnf {
+
+struct Changelog {
+private:
+ time_t timestamp;
+ std::string author;
+ std::string text;
+public:
+ Changelog(time_t timestamp, std::string && author, std::string && text):
+ timestamp(timestamp), author(std::move(author)), text(std::move(text)) {}
+ time_t getTimestamp() const { return timestamp; };
+ const std::string & getAuthor() const { return author; };
+ const std::string & getText() const { return text; };
+};
+
+}
+
+#endif /* __CHANGELOG_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+
+#include "packageset.hpp"
+#include "../dnf-sack.h"
+#include "../hy-util-private.hpp"
+
+namespace libdnf {
+
+class PackageSet::Impl {
+public:
+ Impl(DnfSack* sack);
+ Impl(DnfSack* sack, Map* map);
+ Impl(const PackageSet & pset);
+ ~Impl();
+
+private:
+ friend PackageSet;
+ DnfSack *sack;
+ Map map;
+};
+
+PackageSet::PackageSet(DnfSack* sack) : pImpl(new Impl(sack)) {}
+PackageSet::PackageSet(DnfSack* sack, Map* map_source) : pImpl(new Impl(sack, map_source)) {}
+PackageSet::PackageSet(const PackageSet & pset): pImpl(new Impl(pset)) {}
+PackageSet::PackageSet(PackageSet && pset): pImpl(std::move(pset.pImpl)) {}
+PackageSet::~PackageSet() = default;
+
+PackageSet::Impl::Impl(DnfSack* sack) :
+sack(sack)
+{
+ map_init(&map, dnf_sack_get_pool(sack)->nsolvables);
+}
+PackageSet::Impl::Impl(DnfSack* sack, Map* map_source) : sack(sack)
+{
+ map_init_clone(&map, map_source);
+}
+PackageSet::Impl::Impl(const PackageSet & pset): sack(pset.pImpl->sack)
+{
+ map_init_clone(&map, &pset.pImpl->map);
+}
+PackageSet::Impl::~Impl() { map_free(&map); }
+
+Id
+PackageSet::operator [](unsigned int index) const
+{
+ const unsigned char *ti = pImpl->map.map;
+ const unsigned char *end = ti + pImpl->map.size;
+ unsigned int enabled;
+ Id id;
+
+ while (ti < end) {
+ enabled = _BitCountLookup[*ti];
+
+ if (index >= enabled ){
+ index -= enabled;
+ ti++;
+ continue;
+ }
+ id = (ti - pImpl->map.map) << 3;
+
+ index++;
+ for (unsigned char byte = *ti; index; byte >>= 1) {
+ if ((byte & 0x01))
+ index--;
+ if (index)
+ id++;
+ }
+ return id;
+ }
+ return -1;
+}
+
+PackageSet &
+PackageSet::operator +=(const PackageSet & other)
+{
+ map_or(&pImpl->map, &other.pImpl->map);
+ return *this;
+}
+
+PackageSet &
+PackageSet::operator -=(const PackageSet & other)
+{
+ map_subtract(&pImpl->map, &other.pImpl->map);
+ return *this;
+}
+
+PackageSet &
+PackageSet::operator /=(const PackageSet & other)
+{
+ map_and(&pImpl->map, &other.pImpl->map);
+ return *this;
+}
+
+PackageSet &
+PackageSet::operator +=(const Map * other)
+{
+ map_or(&pImpl->map, const_cast<Map *>(other));
+ return *this;
+}
+
+PackageSet &
+PackageSet::operator -=(const Map * other)
+{
+ map_subtract(&pImpl->map, const_cast<Map *>(other));
+ return *this;
+}
+
+PackageSet &
+PackageSet::operator /=(const Map * other)
+{
+ map_and(&pImpl->map, const_cast<Map *>(other));
+ return *this;
+}
+
+void
+PackageSet::clear()
+{
+ map_empty(&pImpl->map);
+}
+
+bool
+PackageSet::empty()
+{
+ const unsigned char *res = pImpl->map.map;
+ const unsigned char *end = res + pImpl->map.size;
+
+ while (res < end) {
+ if (*res++)
+ return false;
+ }
+ return true;
+}
+
+
+void PackageSet::set(DnfPackage *pkg) { MAPSET(&pImpl->map, dnf_package_get_id(pkg)); }
+void PackageSet::set(Id id) { MAPSET(&pImpl->map, id); }
+bool PackageSet::has(DnfPackage *pkg) const { return MAPTST(&pImpl->map, dnf_package_get_id(pkg)); }
+bool PackageSet::has(Id id) const { return MAPTST(&pImpl->map, id); }
+void PackageSet::remove(Id id) { MAPCLR(&pImpl->map, id); }
+Map *PackageSet::getMap() const { return &pImpl->map; }
+DnfSack *PackageSet::getSack() const { return pImpl->sack; }
+size_t PackageSet::size() const { return map_count(&pImpl->map); }
+
+Id PackageSet::next(Id previous) const
+{
+ const unsigned char *ti = pImpl->map.map;
+ const unsigned char *end = ti + pImpl->map.size;
+ Id id;
+
+ if (previous >= 0) {
+ ti += previous >> 3;
+ unsigned char byte = *ti; // byte with the previous match
+ byte >>= (previous & 7) + 1; // shift away all previous 1 bits
+
+ for (id = previous + 1; byte; byte >>= 1, id++)
+ if (byte & 0x01)
+ return id;
+ ti++;
+ }
+
+ while (ti < end) {
+
+ if (!*ti){
+ ti++;
+ continue;
+ }
+ id = (ti - pImpl->map.map) << 3;
+ for (unsigned char byte = *ti; 1; byte >>= 1, id++) {
+ if (byte & 0x01)
+ return id;
+ }
+ }
+ return -1;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __PACKAGE_SET_HPP
+#define __PACKAGE_SET_HPP
+
+#include <memory>
+#include <solv/bitmap.h>
+#include "../dnf-types.h"
+#include <solv/pooltypes.h>
+#include "../hy-package.h"
+
+namespace libdnf {
+
+struct PackageSet {
+public:
+ PackageSet(DnfSack* sack);
+ PackageSet(DnfSack* sack, Map* map);
+ PackageSet(const PackageSet & pset);
+ PackageSet(PackageSet && pset);
+ ~PackageSet();
+ Id operator [](unsigned int index) const;
+ PackageSet & operator +=(const PackageSet & other);
+ PackageSet & operator -=(const PackageSet & other);
+ PackageSet & operator /=(const PackageSet & other);
+ PackageSet & operator +=(const Map * other);
+ PackageSet & operator -=(const Map * other);
+ PackageSet & operator /=(const Map * other);
+ void clear();
+ bool empty();
+ void set(DnfPackage *pkg);
+ void set(Id id);
+ bool has(DnfPackage *pkg) const;
+ bool has(Id id) const;
+ void remove(Id id);
+ Map *getMap() const;
+ DnfSack *getSack() const;
+ size_t size() const;
+
+ /**
+ * @brief Returns next id in packageset or -1 if end of package set reached
+ *
+ * @param previous Id of previous element
+ * @return Id
+ */
+ Id next(Id previous) const;
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif /* __PACKAGE_SET_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/utils/utils.hpp"
+
+#include <algorithm>
+#include <assert.h>
+#include <fnmatch.h>
+#include <vector>
+
+extern "C" {
+#include <solv/bitmap.h>
+#include <solv/evr.h>
+#include <solv/solver.h>
+#include <solv/selection.h>
+}
+
+#include "query.hpp"
+#include "../hy-iutil-private.hpp"
+#include "../hy-util-private.hpp"
+#include "../hy-iutil.h"
+#include "../nevra.hpp"
+#include "../hy-query-private.hpp"
+#include "../dnf-sack-private.hpp"
+#include "../dnf-advisorypkg.h"
+#include "../dnf-advisory-private.hpp"
+#include "../goal/IdQueue.hpp"
+#include "../goal/Goal-private.hpp"
+#include "advisory.hpp"
+#include "advisorypkg.hpp"
+#include "packageset.hpp"
+
+#include "libdnf/repo/solvable/Dependency.hpp"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+
+
+namespace std {
+
+template<>
+struct default_delete<DnfPackage> {
+ void operator()(DnfPackage * ptr) noexcept { g_object_unref(ptr); }
+};
+
+}
+
+namespace libdnf {
+
+struct NevraID {
+public:
+ NevraID() : name(0), arch(0), evr(0) {};
+ NevraID(const NevraID & src) = default;
+ NevraID(NevraID && src) noexcept = default;
+ NevraID & operator=(const NevraID & src) = default;
+ NevraID & operator=(NevraID && src) = default;
+ Id name;
+ Id arch;
+ Id evr;
+ std::string evr_str;
+ /**
+ * @brief Parsing function for nevra string into name, evr, arch and transforming it into libsolv
+ * Id
+ *
+ * int createNewEVR - `1` will create new id for evr when it is unknown, `0` will exit with false when evr is unknown
+ *
+ * @return bool Returns true if parsing succesful and all elements is known to pool
+ */
+
+ bool parse(Pool * pool, const char * nevraPattern, bool createEVRId);
+};
+
+bool
+NevraID::parse(Pool * pool, const char * nevraPattern, bool createEVRId)
+{
+ const char * evrDelim = nullptr;
+ const char * releaseDelim = nullptr;
+ const char * archDelim = nullptr;
+ const char * end;
+
+ // parse nevra
+ for (end = nevraPattern; *end != '\0'; ++end) {
+ if (*end == '-') {
+ evrDelim = releaseDelim;
+ releaseDelim = end;
+ } else if (*end == '.') {
+ archDelim = end;
+ }
+ }
+
+ // test name presence
+ if (!evrDelim || evrDelim == nevraPattern)
+ return false;
+
+ auto nameLen = evrDelim - nevraPattern;
+
+ // strip epoch "0:" or "00:" and so on
+ // it is similar how libsolv strips "0 "epoch
+ int index = 1;
+ while (evrDelim[index] == '0') {
+ if (evrDelim[++index] == ':') {
+ evrDelim += index;
+ }
+ }
+
+ // test version and arch presence
+ if (releaseDelim - evrDelim <= 1 ||
+ !archDelim || archDelim <= releaseDelim + 1 || archDelim == end - 1)
+ return false;
+
+ // convert strings to Ids
+ if (!(name = pool_strn2id(pool, nevraPattern, nameLen, 0)))
+ return false;
+ ++evrDelim;
+
+ // evr
+ if (createEVRId) {
+ if (!(evr = pool_strn2id(pool, evrDelim, archDelim - evrDelim, 0))) {
+ return false;
+ }
+ } else {
+ evr_str.clear();
+ evr_str.append(evrDelim, archDelim);
+ }
+
+ ++archDelim;
+ if (!(arch = pool_strn2id(pool, archDelim, end - archDelim, 0)))
+ return false;
+
+ return true;
+}
+
+static bool
+nevraIDSorter(const NevraID & first, const NevraID & second)
+{
+ if (first.name != second.name)
+ return first.name < second.name;
+ if (first.arch != second.arch)
+ return first.arch < second.arch;
+ return first.evr < second.evr;
+}
+
+static bool
+nevraCompareLowerSolvable(const NevraID &first, const Solvable &s)
+{
+ if (first.name != s.name)
+ return first.name < s.name;
+ if (first.arch != s.arch)
+ return first.arch < s.arch;
+ return first.evr < s.evr;
+}
+
+static bool
+nevraNameArchKey(const NevraID & first, const NevraID & second)
+{
+ if (first.name != second.name)
+ return first.name < second.name;
+ return first.arch < second.arch;
+}
+
+static bool
+nameArchCompareLowerSolvable(const NevraID &first, const Solvable &s)
+{
+ if (first.name != s.name)
+ return first.name < s.name;
+ return first.arch < s.arch;
+}
+
+static bool
+NameArchSolvableComparator(const Solvable * first, const Solvable * second)
+{
+ if (first->name != second->name)
+ return first->name < second->name;
+ return first->arch < second->arch;
+}
+
+static bool
+NameSolvableComparator(const Solvable * first, const Solvable * second)
+{
+ return first->name < second->name;
+}
+
+
+static bool
+NamePrioritySolvableKey(const Solvable * first, const Solvable * second)
+{
+ if (first->name != second->name)
+ return first->name < second->name;
+ return first->repo->priority > second->repo->priority;
+}
+
+static bool
+NameArchPrioritySolvableKey(const Solvable * first, const Solvable * second)
+{
+ if (first->name != second->name)
+ return first->name < second->name;
+ if (first->arch != second->arch) {
+ return first->arch < second->arch;
+ }
+ return first->repo->priority > second->repo->priority;
+}
+
+struct NameArchEVRComparator {
+ NameArchEVRComparator(Pool * pool) : pool(pool) {};
+ bool operator()(const Solvable * first, const Solvable * second) {
+ if (first->name != second->name) {
+ return first->name < second->name;
+ }
+ if (first->arch != second->arch) {
+ return first->arch < second->arch;
+ }
+ return pool_evrcmp(pool, first->evr, second->evr, EVRCMP_COMPARE) < 0;
+ }
+ bool operator()(const Solvable * solvable, const AdvisoryPkg & pkg) {
+ if (pkg.getName() != solvable->name) {
+ return pkg.getName() > solvable->name;
+ }
+ if (pkg.getArch() != solvable->arch) {
+ return pkg.getArch() > solvable->arch;
+ }
+ return pool_evrcmp(pool, pkg.getEVR(), solvable->evr, EVRCMP_COMPARE) > 0;
+ }
+
+ Pool * pool;
+};
+
+
+static bool
+match_type_num(int keyname) {
+ switch (keyname) {
+ case HY_PKG_EMPTY:
+ case HY_PKG_EPOCH:
+ case HY_PKG_LATEST:
+ case HY_PKG_LATEST_PER_ARCH:
+ case HY_PKG_LATEST_PER_ARCH_BY_PRIORITY:
+ case HY_PKG_UPGRADABLE:
+ case HY_PKG_UPGRADES:
+ case HY_PKG_UPGRADES_BY_PRIORITY:
+ case HY_PKG_DOWNGRADABLE:
+ case HY_PKG_DOWNGRADES:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+match_type_pkg(int keyname) {
+ switch (keyname) {
+ case HY_PKG:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_OBSOLETES_BY_PRIORITY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+match_type_reldep(int keyname) {
+ switch (keyname) {
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_PROVIDES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUPPLEMENTS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+match_type_str(int keyname) {
+ switch (keyname) {
+ case HY_PKG_ADVISORY:
+ case HY_PKG_ADVISORY_BUG:
+ case HY_PKG_ADVISORY_CVE:
+ case HY_PKG_ADVISORY_SEVERITY:
+ case HY_PKG_ADVISORY_TYPE:
+ case HY_PKG_ARCH:
+ case HY_PKG_DESCRIPTION:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_EVR:
+ case HY_PKG_FILE:
+ case HY_PKG_LOCATION:
+ case HY_PKG_NAME:
+ case HY_PKG_NEVRA:
+ case HY_PKG_NEVRA_STRICT:
+ case HY_PKG_PROVIDES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_RELEASE:
+ case HY_PKG_REPONAME:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_SOURCERPM:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUMMARY:
+ case HY_PKG_SUPPLEMENTS:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_URL:
+ case HY_PKG_VERSION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+valid_filter_str(int keyname, int cmp_type)
+{
+ if (!match_type_str(keyname))
+ return false;
+
+ cmp_type &= ~HY_NOT; // hy_query_run always handles NOT
+ switch (keyname) {
+ case HY_PKG_LOCATION:
+ case HY_PKG_SOURCERPM:
+ case HY_PKG_NEVRA_STRICT:
+ return cmp_type == HY_EQ;
+ case HY_PKG_ARCH:
+ return cmp_type & HY_EQ || cmp_type & HY_GLOB;
+ case HY_PKG_NAME:
+ return cmp_type & HY_EQ || cmp_type & HY_GLOB || cmp_type & HY_SUBSTR;
+ default:
+ return true;
+ }
+}
+
+static bool
+valid_filter_num(int keyname, int cmp_type)
+{
+ if (!match_type_num(keyname))
+ return false;
+
+ cmp_type &= ~HY_NOT; // hy_query_run always handles NOT
+ if (cmp_type & (HY_ICASE | HY_SUBSTR | HY_GLOB))
+ return false;
+ switch (keyname) {
+ case HY_PKG:
+ return cmp_type == HY_EQ;
+ default:
+ return true;
+ }
+}
+
+static bool
+valid_filter_pkg(int keyname, int cmp_type)
+{
+ if (!match_type_pkg(keyname) && !match_type_reldep(keyname))
+ return false;
+ return cmp_type == HY_EQ || cmp_type == HY_NEQ;
+}
+
+static bool
+valid_filter_reldep(int keyname)
+{
+ return match_type_reldep(keyname);
+}
+
+static Id
+reldep_keyname2id(int keyname)
+{
+ switch(keyname) {
+ case HY_PKG_CONFLICTS:
+ return SOLVABLE_CONFLICTS;
+ case HY_PKG_ENHANCES:
+ return SOLVABLE_ENHANCES;
+ case HY_PKG_OBSOLETES:
+ return SOLVABLE_OBSOLETES;
+ case HY_PKG_REQUIRES:
+ return SOLVABLE_REQUIRES;
+ case HY_PKG_RECOMMENDS:
+ return SOLVABLE_RECOMMENDS;
+ case HY_PKG_SUGGESTS:
+ return SOLVABLE_SUGGESTS;
+ case HY_PKG_SUPPLEMENTS:
+ return SOLVABLE_SUPPLEMENTS;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+static Id
+di_keyname2id(int keyname)
+{
+ switch(keyname) {
+ case HY_PKG_DESCRIPTION:
+ return SOLVABLE_DESCRIPTION;
+ case HY_PKG_NAME:
+ return SOLVABLE_NAME;
+ case HY_PKG_URL:
+ return SOLVABLE_URL;
+ case HY_PKG_ARCH:
+ return SOLVABLE_ARCH;
+ case HY_PKG_EVR:
+ return SOLVABLE_EVR;
+ case HY_PKG_SUMMARY:
+ return SOLVABLE_SUMMARY;
+ case HY_PKG_FILE:
+ return SOLVABLE_FILELIST;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+static int
+type2flags(int type, int keyname)
+{
+ int ret = 0;
+ if (keyname == HY_PKG_FILE)
+ ret |= SEARCH_FILES | SEARCH_COMPLETE_FILELIST;
+ if (type & HY_ICASE)
+ ret |= SEARCH_NOCASE;
+
+ type &= ~HY_COMPARISON_FLAG_MASK;
+ switch (type) {
+ case HY_EQ:
+ return ret | SEARCH_STRING;
+ case HY_SUBSTR:
+ return ret | SEARCH_SUBSTRING;
+ case HY_GLOB:
+ return ret | SEARCH_GLOB;
+ default:
+ assert(0); // not implemented
+ return 0;
+ }
+}
+
+static char *
+pool_solvable_epoch_optional_2str(Pool *pool, const Solvable *s, gboolean with_epoch)
+{
+ const char *e;
+ const char *name = pool_id2str(pool, s->name);
+ const char *evr = pool_id2str(pool, s->evr);
+ const char *arch = pool_id2str(pool, s->arch);
+ bool present_epoch = false;
+
+ for (e = evr + 1; *e != '-' && *e != '\0'; ++e) {
+ if (*e == ':') {
+ present_epoch = true;
+ break;
+ }
+ }
+ char *output_string;
+ int evr_length, arch_length;
+ int extra_epoch_length = 0;
+ int name_length = strlen(name);
+ evr_length = strlen(evr);
+ arch_length = strlen(arch);
+ if (!present_epoch && with_epoch) {
+ extra_epoch_length = 2;
+ } else if (present_epoch && !with_epoch) {
+ extra_epoch_length = evr - e - 1;
+ }
+
+ output_string = pool_alloctmpspace(
+ pool, name_length + evr_length + extra_epoch_length + arch_length + 3);
+
+ strcpy(output_string, name);
+
+ if (evr_length || extra_epoch_length > 0) {
+ output_string[name_length++] = '-';
+
+ if (extra_epoch_length > 0) {
+ output_string[name_length++] = '0';
+ output_string[name_length++] = ':';
+ output_string[name_length] = '\0';
+ }
+ }
+
+ if (evr_length) {
+ if (extra_epoch_length >= 0) {
+ strcpy(output_string + name_length, evr);
+ } else {
+ strcpy(output_string + name_length, evr - extra_epoch_length);
+ evr_length = evr_length + extra_epoch_length;
+ }
+ }
+
+ if (arch_length) {
+ output_string[name_length + evr_length] = '.';
+ strcpy(output_string + name_length + evr_length + 1, arch);
+ }
+ return output_string;
+}
+
+static int
+filter_latest_sortcmp(const void *ap, const void *bp, void *dp)
+{
+ auto pool = static_cast<Pool *>(dp);
+ Solvable *sa = pool->solvables + *(Id *)ap;
+ Solvable *sb = pool->solvables + *(Id *)bp;
+ int r;
+ r = sa->name - sb->name;
+ if (r)
+ return r;
+ r = pool_evrcmp(pool, sb->evr, sa->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+filter_latest_sortcmp_byarch(const void *ap, const void *bp, void *dp)
+{
+ auto pool = static_cast<Pool *>(dp);
+ Solvable *sa = pool->solvables + *(Id *)ap;
+ Solvable *sb = pool->solvables + *(Id *)bp;
+ int r;
+ r = sa->name - sb->name;
+ if (r)
+ return r;
+ r = sa->arch - sb->arch;
+ if (r)
+ return r;
+ r = pool_evrcmp(pool, sb->evr, sa->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+filter_latest_sortcmp_byarch_bypriority(const void *ap, const void *bp, void *dp)
+{
+ auto pool = static_cast<Pool *>(dp);
+ Solvable *sa = pool->solvables + *(Id *)ap;
+ Solvable *sb = pool->solvables + *(Id *)bp;
+ int r;
+ r = sa->name - sb->name;
+ if (r)
+ return r;
+ r = sa->arch - sb->arch;
+ if (r)
+ return r;
+ r = sb->repo->priority - sa->repo->priority;
+ if (r)
+ return r;
+ r = pool_evrcmp(pool, sb->evr, sa->evr, EVRCMP_COMPARE);
+ if (r)
+ return r;
+ return *(Id *)ap - *(Id *)bp;
+}
+
+/**
+* @brief Add packages from given block into a map
+*
+* @param pool: Package pool
+* @param m: Map of query results complying the filter
+* @param samename: Queue containing the block
+* @param start_block: Start of the block
+* @param stop_block: End of the block
+* @param latest: Number of first packages in the block to add into the map.
+* If negative, it's number of first packages in the block to exclude.
+*/
+static void
+add_latest_to_map(const Pool *pool, Map *m, Queue *samename,
+ int start_block, int stop_block, int latest)
+{
+ Solvable *solv_element, *solv_previous_element;
+ int version_counter = 0;
+ solv_previous_element = pool->solvables + samename->elements[start_block];
+ Id id_previous_evr = solv_previous_element->evr;
+ for (int pos = start_block; pos < stop_block; ++pos) {
+ Id id_element = samename->elements[pos];
+ solv_element = pool->solvables + id_element;
+ Id id_current_evr = solv_element->evr;
+ if (id_previous_evr != id_current_evr) {
+ version_counter += 1;
+ id_previous_evr = id_current_evr;
+ }
+ if (latest > 0) {
+ if (!(version_counter < latest)) {
+ return;
+ }
+ } else {
+ if (version_counter < -latest) {
+ continue;
+ }
+ }
+ MAPSET(m, id_element);
+ }
+}
+
+static void
+add_duplicates_to_map(Pool *pool, Map *res, IdQueue & samename, int start_block, int stop_block)
+{
+ Solvable *s_first, *s_second;
+ for (int pos = start_block; pos < stop_block; ++pos) {
+ Id id_first = samename[pos];
+ s_first = pool->solvables + id_first;
+ for (int pos2 = pos + 1; pos2 < stop_block; ++pos2) {
+ Id id_second = samename[pos2];
+ s_second = pool->solvables + id_second;
+ if ((s_first->evr == s_second->evr) && (s_first->arch != s_second->arch)) {
+ continue;
+ }
+ MAPSET(res, id_first);
+ MAPSET(res, id_second);
+ }
+ }
+}
+
+static bool
+advisoryPkgSort(const AdvisoryPkg &first, const AdvisoryPkg &second)
+{
+ if (first.getName() != second.getName())
+ return first.getName() < second.getName();
+ if (first.getArch() != second.getArch())
+ return first.getArch() < second.getArch();
+ return first.getEVR() < second.getEVR();
+}
+
+static bool
+advisoryPkgCompareSolvable(const AdvisoryPkg &first, const Solvable &s)
+{
+ if (first.getName() != s.name)
+ return first.getName() < s.name;
+ if (first.getArch() != s.arch)
+ return first.getArch() < s.arch;
+ return first.getEVR() < s.evr;
+}
+
+static bool
+advisoryPkgCompareSolvableNameArch(const AdvisoryPkg &first, const Solvable &s)
+{
+ if (first.getName() != s.name)
+ return first.getName() < s.name;
+ return first.getArch() < s.arch;
+}
+
+static bool
+SolvableCompareAdvisoryPkgNameArch(const Solvable * s, const AdvisoryPkg & first)
+{
+ if (first.getName() != s->name)
+ return first.getName() > s->name;
+ return first.getArch() > s->arch;
+}
+
+static char *
+copyFilterChar(const char * match, int keyname)
+{
+ if (!match)
+ throw std::runtime_error("Query can not accept NULL for STR match");
+ size_t len = strlen(match);
+ char * matchNew = new char[len + 1];
+ if (keyname == HY_PKG_FILE && len > 1 && match[--len] == '/') {
+ strncpy(matchNew, match, len);
+ matchNew[len] = '\0';
+ return matchNew;
+ }
+ return strcpy(matchNew, match);
+}
+
+class Filter::Impl {
+public:
+ ~Impl();
+private:
+ friend struct Filter;
+ int cmpType;
+ int keyname;
+ int matchType;
+ std::vector<_Match> matches;
+};
+Filter::Filter(int keyname, int cmp_type, int match) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_NUM;
+ _Match match_in;
+ match_in.num = match;
+ pImpl->matches.push_back(match_in);
+}
+Filter::Filter(int keyname, int cmp_type, int nmatches, const int *matches) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_NUM;
+ pImpl->matches.reserve(nmatches);
+ for (int i = 0; i < nmatches; ++i) {
+ _Match match_in;
+ match_in.num = matches[i];
+ pImpl->matches.push_back(match_in);
+ }
+}
+Filter::Filter(int keyname, int cmp_type, const DnfPackageSet *pset) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_PKG;
+ _Match match_in;
+ match_in.pset = new PackageSet(*pset);
+ pImpl->matches.push_back(match_in);
+}
+Filter::Filter(int keyname, int cmp_type, const Dependency * reldep) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_RELDEP;
+ _Match match_in;
+ match_in.reldep = reldep->getId();
+ pImpl->matches.push_back(match_in);
+}
+Filter::Filter(int keyname, int cmp_type, const DependencyContainer * reldeplist) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_RELDEP;
+ const int nmatches = reldeplist->count();
+ pImpl->matches.reserve(nmatches);
+ for (int i = 0; i < nmatches; ++i) {
+ _Match match_in;
+ match_in.reldep = reldeplist->getId(i);
+ pImpl->matches.push_back(match_in);
+ }
+}
+Filter::Filter(int keyname, int cmp_type, const char *match) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_STR;
+ _Match match_in;
+ match_in.str = copyFilterChar(match, keyname);
+ pImpl->matches.push_back(match_in);
+}
+Filter::Filter(int keyname, int cmp_type, const char **matches) : pImpl(new Impl)
+{
+ pImpl->keyname = keyname;
+ pImpl->cmpType = cmp_type;
+ pImpl->matchType = _HY_STR;
+ const unsigned nmatches = g_strv_length((gchar**)matches);
+ pImpl->matches.reserve(nmatches);
+ for (unsigned int i = 0; i < nmatches; ++i) {
+ _Match match_in;
+ match_in.str = copyFilterChar(matches[i], keyname);
+ pImpl->matches.push_back(match_in);
+ }
+}
+
+Filter::~Filter() = default;
+
+Filter::Impl::~Impl()
+{
+ for (auto & match : matches) {
+ switch (matchType) {
+ case _HY_PKG:
+ delete match.pset;
+ break;
+ case _HY_STR:
+ delete[] match.str;
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+int Filter::getKeyname() const noexcept { return pImpl->keyname; }
+int Filter::getCmpType() const noexcept { return pImpl->cmpType; }
+int Filter::getMatchType() const noexcept { return pImpl->matchType; }
+const std::vector< _Match >& Filter::getMatches() const noexcept { return pImpl->matches; }
+
+class Query::Impl {
+public:
+ ~Impl();
+private:
+ friend struct Query;
+ Impl(DnfSack* sack, Query::ExcludeFlags flags = Query::ExcludeFlags::APPLY_EXCLUDES);
+ Impl(const Query::Impl & src_query);
+ Impl & operator= (const Impl & src);
+ bool applied{0};
+ DnfSack *sack;
+ Query::ExcludeFlags flags;
+ std::unique_ptr<PackageSet> result;
+ std::vector<Filter> filters;
+ void apply();
+ Map *considered_cached = nullptr;
+
+ /**
+ * @brief It accepts strings of whole NEVRA and apply them to the query. It requires full
+ * NEVRA without globs.
+ * For dnf-2.8.9-1.fc27.noarch it accepts dnf-0:2.8.9-1.fc27.noarch or dnf-2.8.9-1.fc27.noarch
+ * But for package gedit-3:3.22.1-2.fc27.x86_64 the string gedit-3.22.1-2.fc27.x86_64 is
+ * incorrect and there will be no result for the query.
+ *
+ * @param cmpType p_cmpType: Allowed compare types - only HY_EQ, HY_GT, HY_LT optionaly combined with HY_NOT
+ * @param matches p_matches: Patterns to match
+ */
+ void filterNevraStrict(int cmpType, const char **matches);
+ void initResult();
+ void filterPkg(const Filter & f, Map *m);
+ void filterDepSolvable(const Filter & f, Map * m);
+ void filterRcoReldep(const Filter & f, Map *m);
+ void filterName(const Filter & f, Map *m);
+ void filterEpoch(const Filter & f, Map *m);
+ void filterEvr(const Filter & f, Map *m);
+ void filterNevra(const Filter & f, Map *m);
+ void filterVersion(const Filter & f, Map *m);
+ void filterRelease(const Filter & f, Map *m);
+ void filterArch(const Filter & f, Map *m);
+ void filterSourcerpm(const Filter & f, Map *m);
+ void filterObsoletes(const Filter & f, Map *m);
+ void filterObsoletesByPriority(const Filter & f, Map *m);
+ void filterProvidesReldep(const Filter & f, Map *m);
+ void filterReponame(const Filter & f, Map *m);
+ void filterLocation(const Filter & f, Map *m);
+ void filterAdvisory(const Filter & f, Map *m, int keyname);
+ void filterLatest(const Filter & f, Map *m);
+ void filterUpdown(const Filter & f, Map *m);
+ void filterUpdownByPriority(const Filter & f, Map *m);
+ void filterUpdownAble(const Filter &f, Map *m);
+ void filterDataiterator(const Filter & f, Map *m);
+ int filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove);
+ void obsoletesByPriority(Pool * pool, Solvable * candidate, Map * m, const Map * target, int obsprovides);
+
+ bool isGlob(const std::vector<const char *> &matches) const;
+};
+
+Query::Impl::~Impl()
+{
+ if (considered_cached)
+ free_map_fully(considered_cached);
+}
+
+Query::Impl::Impl(DnfSack* sack, Query::ExcludeFlags flags)
+: sack(sack), flags(flags) {}
+
+Query::Impl::Impl(const Query::Impl & src)
+: applied(src.applied)
+, sack(src.sack)
+, flags(src.flags)
+, filters(src.filters)
+{
+ if (src.result) {
+ result.reset(new PackageSet(*src.result.get()));
+ }
+}
+
+Query::Impl &
+Query::Impl::operator=(const Query::Impl & src)
+{
+ applied = src.applied;
+ sack = src.sack;
+ flags = src.flags;
+ filters = src.filters;
+ if (src.result) {
+ result.reset(new PackageSet(*src.result.get()));
+ } else {
+ result.reset();
+ }
+ return *this;
+}
+
+Query::Query(const Query & query_src) : pImpl(new Impl(*query_src.pImpl)) {}
+Query::Query(DnfSack *sack, Query::ExcludeFlags flags) : pImpl(new Impl(sack, flags)) {}
+Query::~Query() = default;
+
+Query & Query::operator=(const Query & query_src) { *pImpl = *query_src.pImpl; return *this; }
+
+Map *
+Query::getResult() noexcept
+{
+ if (pImpl->result)
+ return pImpl->result->getMap();
+ else
+ return nullptr;
+}
+
+const Map * Query::getResult() const noexcept { return pImpl->result->getMap(); }
+PackageSet * Query::getResultPset()
+{
+ pImpl->apply();
+ return pImpl->result.get();
+}
+bool Query::getApplied() const noexcept { return pImpl->applied; }
+DnfSack * Query::getSack() { return pImpl->sack; }
+
+void
+Query::clear()
+{
+ pImpl->applied = false;
+ pImpl->result.reset();
+ pImpl->filters.clear();
+}
+
+size_t
+Query::size()
+{
+ apply();
+ return pImpl->result->size();
+}
+
+
+int
+Query::addFilter(int keyname, int cmp_type, int match)
+{
+ if (!valid_filter_num(keyname, cmp_type))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ pImpl->filters.push_back(Filter(keyname, cmp_type, match));
+ return 0;
+}
+int
+Query::addFilter(int keyname, int cmp_type, int nmatches, const int *matches)
+{
+ if (!valid_filter_num(keyname, cmp_type))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ pImpl->filters.push_back(Filter(keyname, cmp_type, nmatches, matches));
+ return 0;
+}
+int
+Query::addFilter(int keyname, int cmp_type, const DnfPackageSet *pset)
+{
+ if (!valid_filter_pkg(keyname, cmp_type))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ pImpl->filters.push_back(Filter(keyname, cmp_type, pset));
+ return 0;
+}
+int
+Query::addFilter(int keyname, const Dependency * reldep)
+{
+ if (!valid_filter_reldep(keyname))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ pImpl->filters.push_back(Filter(keyname, HY_EQ, reldep));
+ return 0;
+}
+int
+Query::addFilter(int keyname, const DependencyContainer * reldeplist)
+{
+ if (!valid_filter_reldep(keyname))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ if (reldeplist->count()) {
+ pImpl->filters.push_back(Filter(keyname, HY_EQ, reldeplist));
+ } else {
+ pImpl->filters.push_back(Filter(HY_PKG_EMPTY, HY_EQ, 1));
+ }
+ return 0;
+}
+int
+Query::addFilter(int keyname, int cmp_type, const char *match)
+{
+ if (keyname == HY_PKG_NEVRA_STRICT) {
+ if (!(cmp_type & HY_EQ || cmp_type & HY_GT || cmp_type & HY_LT))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->apply();
+ const char * matches[2]{match, nullptr};
+ pImpl->filterNevraStrict(cmp_type, matches);
+ return 0;
+ }
+
+ if ((cmp_type & HY_GLOB) && !hy_is_glob_pattern(match))
+ cmp_type = (cmp_type & ~HY_GLOB) | HY_EQ;
+
+ if (!valid_filter_str(keyname, cmp_type))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ switch (keyname) {
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_PROVIDES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUPPLEMENTS: {
+ DnfSack *sack = pImpl->sack;
+
+ if (cmp_type == HY_GLOB) {
+ DependencyContainer reldeplist(sack);
+ if (!reldeplist.addReldepWithGlob(match)) {
+ return addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+ }
+ return addFilter(keyname, &reldeplist);
+ } else {
+ try {
+ Dependency reldep(sack, match);
+ int ret = addFilter(keyname, &reldep);
+ return ret;
+ }
+ catch (...) {
+ return addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+ }
+ }
+ }
+ default: {
+ pImpl->filters.push_back(Filter(keyname, cmp_type, match));
+ return 0;
+ }
+ }
+}
+int
+Query::addFilter(int keyname, int cmp_type, const char **matches)
+{
+ if (keyname == HY_PKG_NEVRA_STRICT) {
+ if (!(cmp_type & HY_EQ || cmp_type & HY_GT || cmp_type & HY_LT))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->apply();
+ pImpl->filterNevraStrict(cmp_type, matches);
+ return 0;
+ }
+
+ if (cmp_type & HY_GLOB) {
+ bool is_glob = false;
+ for (const char **match = matches; *match != NULL; match++) {
+ if (hy_is_glob_pattern(*match)) {
+ is_glob = true;
+ break;
+ }
+ }
+ if (!is_glob) {
+ cmp_type = (cmp_type & ~HY_GLOB) | HY_EQ;
+ }
+ }
+ if (!valid_filter_str(keyname, cmp_type))
+ return DNF_ERROR_BAD_QUERY;
+ pImpl->applied = false;
+ switch (keyname) {
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_PROVIDES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUPPLEMENTS: {
+ DnfSack *sack = pImpl->sack;
+ const unsigned nmatches = g_strv_length((gchar**)matches);
+ DependencyContainer reldeplist(sack);
+ if (cmp_type == HY_GLOB) {
+ for (unsigned int i = 0; i < nmatches; ++i) {
+ reldeplist.addReldepWithGlob(matches[i]);
+ }
+ } else {
+ for (unsigned int i = 0; i < nmatches; ++i) {
+ reldeplist.addReldep(matches[i]);
+ }
+ }
+ return addFilter(keyname, &reldeplist);
+ }
+ default: {
+ pImpl->filters.push_back(Filter(keyname, cmp_type, matches));
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int
+Query::addFilter(HyNevra nevra, bool icase)
+{
+ if (!nevra->getName().empty() && nevra->getName() != "*") {
+ if (icase)
+ addFilter(HY_PKG_NAME, HY_GLOB|HY_ICASE, nevra->getName().c_str());
+ else
+ addFilter(HY_PKG_NAME, HY_GLOB, nevra->getName().c_str());
+ }
+ if (nevra->getEpoch() != -1)
+ addFilter(HY_PKG_EPOCH, HY_EQ, nevra->getEpoch());
+ if (!nevra->getVersion().empty() && nevra->getVersion() != "*")
+ addFilter(HY_PKG_VERSION, HY_GLOB, nevra->getVersion().c_str());
+ if (!nevra->getRelease().empty() && nevra->getRelease() != "*")
+ addFilter(HY_PKG_RELEASE, HY_GLOB, nevra->getRelease().c_str());
+ if (!nevra->getArch().empty() && nevra->getArch() != "*")
+ addFilter(HY_PKG_ARCH, HY_GLOB, nevra->getArch().c_str());
+ return 0;
+}
+
+void
+Query::Impl::filterNevraStrict(int cmpType, const char **matches)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ std::vector<NevraID> compareSet;
+ const unsigned nmatches = g_strv_length((gchar**)matches);
+ compareSet.reserve(nmatches);
+
+ bool createEVRId = true;
+ if (cmpType & HY_LT || cmpType & HY_GT) {
+ createEVRId = false;
+ }
+
+ for (unsigned int i = 0; i < nmatches; ++i) {
+ const char * nevraPattern = matches[i];
+ if (!nevraPattern)
+ throw std::runtime_error("Query can not accept NULL for STR match");
+ NevraID nevraId;
+ if (nevraId.parse(pool, nevraPattern, createEVRId)) {
+ compareSet.push_back(std::move(nevraId));
+ }
+ }
+ if (compareSet.empty()) {
+ if (!(cmpType & HY_NOT))
+ map_empty(result->getMap());
+ return;
+ }
+ Map nevraResult;
+ map_init(&nevraResult, pool->nsolvables);
+
+ // if cmpType == HY_EQ or cmpType == (HY_EQ | HY_NOT) -> performance optimization
+ if (createEVRId) {
+ if (compareSet.size() > 1) {
+ std::sort(compareSet.begin(), compareSet.end(), nevraIDSorter);
+
+ Id id = -1;
+ while (true) {
+ id = result->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(compareSet.begin(), compareSet.end(), *s,
+ nevraCompareLowerSolvable);
+ if (low != compareSet.end() && low->name == s->name && low->arch == s->arch
+ && low->evr == s->evr) {
+ MAPSET(&nevraResult, id);
+ }
+ }
+ } else {
+ NevraID & nevraId = compareSet[0];
+ Id id = -1;
+ while (true) {
+ id = result->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ if (nevraId.name == s->name && nevraId.arch == s->arch && nevraId.evr == s->evr) {
+ MAPSET(&nevraResult, id);
+ }
+ }
+ }
+ } else {
+ if (compareSet.size() > 1) {
+ std::sort(compareSet.begin(), compareSet.end(), nevraNameArchKey);
+
+ Id id = -1;
+ while (true) {
+ id = result->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(compareSet.begin(), compareSet.end(), *s,
+ nameArchCompareLowerSolvable);
+ while (low != compareSet.end() && low->name == s->name && low->arch == s->arch) {
+ int cmp = pool_evrcmp_str(
+ pool, pool_id2str(pool, s->evr), low->evr_str.c_str(), EVRCMP_COMPARE);
+
+ if ((cmp > 0 && cmpType & HY_GT) || (cmp < 0 && cmpType & HY_LT)
+ || (cmp == 0 && cmpType & HY_EQ)) {
+ MAPSET(&nevraResult, id);
+ break;
+ }
+ ++low;
+ }
+ }
+ } else {
+ auto & nevraId = compareSet[0];
+ Id id = -1;
+ while (true) {
+ id = result->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ if (nevraId.name == s->name && nevraId.arch == s->arch) {
+ int cmp = pool_evrcmp_str(
+ pool, pool_id2str(pool, s->evr), nevraId.evr_str.c_str(), EVRCMP_COMPARE);
+ if ((cmp > 0 && cmpType & HY_GT) || (cmp < 0 && cmpType & HY_LT) ||
+ (cmp == 0 && cmpType & HY_EQ)) {
+ MAPSET(&nevraResult, id);
+ }
+ }
+ }
+ }
+ }
+ if (cmpType & HY_NOT)
+ map_subtract(result->getMap(), &nevraResult);
+ else
+ map_and(result->getMap(), &nevraResult);
+ map_free(&nevraResult);
+}
+
+void
+Query::Impl::initResult()
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Id solvid;
+ int sack_pool_nsolvables = dnf_sack_get_pool_nsolvables(sack);
+ if (sack_pool_nsolvables != 0 && sack_pool_nsolvables == pool->nsolvables)
+ result.reset(dnf_sack_get_pkg_solvables(sack));
+ else {
+ result.reset(new PackageSet(sack));
+ FOR_PKG_SOLVABLES(solvid)
+ result->set(solvid);
+ dnf_sack_set_pkg_solvables(sack, result->getMap(), pool->nsolvables);
+ }
+ if (flags == Query::ExcludeFlags::APPLY_EXCLUDES) {
+ dnf_sack_recompute_considered(sack);
+ if (pool->considered)
+ map_and(result->getMap(), pool->considered);
+ } else {
+ dnf_sack_recompute_considered_map(sack, &considered_cached, flags);
+ if (considered_cached) {
+ map_and(result->getMap(), considered_cached);
+ }
+ }
+}
+
+void
+Query::Impl::filterPkg(const Filter & f, Map *m)
+{
+ assert(f.getMatches().size() == 1);
+ assert(f.getMatchType() == _HY_PKG);
+
+ map_free(m);
+ map_init_clone(m, dnf_packageset_get_map(f.getMatches()[0].pset));
+}
+
+void
+Query::Impl::filterDepSolvable(const Filter & f, Map * m)
+{
+ assert(f.getMatchType() == _HY_PKG);
+ assert(f.getMatches().size() == 1);
+
+ dnf_sack_make_provides_ready(sack);
+ Pool * pool = dnf_sack_get_pool(sack);
+ Id rco_key = reldep_keyname2id(f.getKeyname());
+
+ IdQueue out;
+
+ const auto filter_pset = f.getMatches()[0].pset;
+ Id id = -1;
+ while ((id = filter_pset->next(id)) != -1) {
+ out.clear();
+
+ // queue_push2 because we are creating a selection, which contains pairs
+ // of <flags, Id>, SOLVER_SOOLVABLE_ALL is a special flag which includes
+ // all packages from specified pool, Id is ignored.
+ out.pushBack(SOLVER_SOLVABLE_ALL, 0);
+
+ int flags = 0;
+ flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+ selection_make_matchsolvable(pool, out.getQueue(), id, flags, rco_key, 0);
+
+ // Queue from selection_make_matchsolvable is a selection, which means
+ // it conntains pairs <flags, Id>, flags refers to how was the Id
+ // matched, that is not important here, so skip it and iterate just
+ // over the Ids.
+ for (int j = 1; j < out.size(); j += 2) {
+ MAPSET(m, out[j]);
+ }
+ }
+}
+
+void
+Query::Impl::filterRcoReldep(const Filter & f, Map *m)
+{
+ assert(f.getMatchType() == _HY_RELDEP);
+
+ Pool *pool = dnf_sack_get_pool(sack);
+ Id rco_key = reldep_keyname2id(f.getKeyname());
+ Queue rco;
+ auto resultPset = result.get();
+
+ queue_init(&rco);
+ Id resultId = -1;
+ while ((resultId = resultPset->next(resultId)) != -1) {
+ Solvable *s = pool_id2solvable(pool, resultId );
+ for (auto match : f.getMatches()) {
+ Id reldepFilterId = match.reldep;
+
+ queue_empty(&rco);
+ solvable_lookup_idarray(s, rco_key, &rco);
+ for (int j = 0; j < rco.count; ++j) {
+ Id reldepIdFromSolvable = rco.elements[j];
+
+ if (pool_match_dep(pool, reldepFilterId, reldepIdFromSolvable )) {
+ MAPSET(m, resultId );
+ goto nextId;
+ }
+ }
+ }
+ nextId:;
+ }
+ queue_free(&rco);
+}
+
+void
+Query::Impl::filterName(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ const int cmpType= f.getCmpType();
+ auto resultPset = result.get();
+
+ if ((cmpType & HY_EQ) && !(cmpType & HY_ICASE)) {
+ Id match_name_id = 0;
+ if (f.getMatches().size() < 3) {
+ for (auto match_union : f.getMatches()) {
+ const char *match = match_union.str;
+ match_name_id = pool_str2id(pool, match, 0);
+ if (match_name_id == 0)
+ continue;
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (match_name_id == s->name)
+ MAPSET(m, id);
+ continue;
+ }
+ }
+ return;
+ }
+ std::vector<Id> names;
+ for (auto match_union : f.getMatches()) {
+ const char *match = match_union.str;
+ match_name_id = pool_str2id(pool, match, 0);
+ if (match_name_id == 0)
+ continue;
+ names.push_back(match_name_id);
+ }
+ std::sort(names.begin(), names.end());
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(names.begin(), names.end(), s->name);
+ if (low != names.end() && (*low) == s->name) {
+ MAPSET(m, id);
+ }
+ }
+ return;
+ }
+
+ for (auto match_union : f.getMatches()) {
+ const char *match = match_union.str;
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+
+ Solvable *s = pool_id2solvable(pool, id);
+ if (cmpType & HY_ICASE) {
+ const char *name = pool_id2str(pool, s->name);
+ if (cmpType & HY_SUBSTR) {
+ if (strcasestr(name, match) != NULL)
+ MAPSET(m, id);
+ continue;
+ }
+ if (cmpType & HY_EQ) {
+ if (strcasecmp(name, match) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+ if (cmpType & HY_GLOB) {
+ if (fnmatch(match, name, FNM_CASEFOLD) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+ continue;
+ }
+
+ const char *name = pool_id2str(pool, s->name);
+ if (cmpType & HY_GLOB) {
+ if (fnmatch(match, name, 0) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+ if (cmpType & HY_SUBSTR) {
+ if (strstr(name, match) != NULL)
+ MAPSET(m, id);
+ continue;
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterEpoch(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ auto resultPset = result.get();
+
+ for (auto match : f.getMatches()) {
+ unsigned long epoch = match.num;
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+
+ Solvable *s = pool_id2solvable(pool, id);
+ if (s->evr == ID_EMPTY)
+ continue;
+
+ const char *evr = pool_id2str(pool, s->evr);
+ unsigned long pkg_epoch = pool_get_epoch(pool, evr);
+
+ if ((pkg_epoch > epoch && cmp_type & HY_GT) ||
+ (pkg_epoch < epoch && cmp_type & HY_LT) ||
+ (pkg_epoch == epoch && cmp_type & HY_EQ))
+ MAPSET(m, id);
+ }
+ }
+}
+
+void
+Query::Impl::filterEvr(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ auto resultPset = result.get();
+
+ for (auto match : f.getMatches()) {
+ Id match_evr = pool_str2id(pool, match.str, 1);
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+ int cmp = pool_evrcmp(pool, s->evr, match_evr, EVRCMP_COMPARE);
+
+ if ((cmp > 0 && cmp_type & HY_GT) || (cmp < 0 && cmp_type & HY_LT) ||
+ (cmp == 0 && cmp_type & HY_EQ)) {
+ MAPSET(m, id);
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterNevra(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ int fn_flags = (HY_ICASE & cmp_type) ? FNM_CASEFOLD : 0;
+ auto resultPset = result.get();
+
+ for (auto match : f.getMatches()) {
+ const char *nevra_pattern = match.str;
+ if (strpbrk(nevra_pattern, "(/=<> "))
+ continue;
+
+ gboolean present_epoch = strchr(nevra_pattern, ':') != NULL;
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+
+ char* nevra = pool_solvable_epoch_optional_2str(pool, s, present_epoch);
+ if (!(HY_GLOB & cmp_type)) {
+ if (HY_ICASE & cmp_type) {
+ if (strcasecmp(nevra_pattern, nevra) == 0)
+ MAPSET(m, id);
+ } else {
+ if (strcmp(nevra_pattern, nevra) == 0)
+ MAPSET(m, id);
+ }
+ } else if (fnmatch(nevra_pattern, nevra, fn_flags) == 0) {
+ MAPSET(m, id);
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterVersion(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+ char *filter_vr = solv_dupjoin(match, "-0", NULL);
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ char *e, *v, *r;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (s->evr == ID_EMPTY)
+ continue;
+ const char *evr = pool_id2str(pool, s->evr);
+
+ pool_split_evr(pool, evr, &e, &v, &r);
+
+ if (cmp_type & HY_GLOB) {
+ if (fnmatch(match, v, 0) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+
+ char *vr = pool_tmpjoin(pool, v, "-0", NULL);
+ int cmp = pool_evrcmp_str(pool, vr, filter_vr, EVRCMP_COMPARE);
+ if ((cmp > 0 && cmp_type & HY_GT) ||
+ (cmp < 0 && cmp_type & HY_LT) ||
+ (cmp == 0 && cmp_type & HY_EQ)) {
+ MAPSET(m, id);
+ }
+ }
+ solv_free(filter_vr);
+ }
+}
+
+void
+Query::Impl::filterRelease(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+ char *filter_vr = solv_dupjoin("0-", match, NULL);
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ char *e, *v, *r;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (s->evr == ID_EMPTY)
+ continue;
+ const char *evr = pool_id2str(pool, s->evr);
+
+ pool_split_evr(pool, evr, &e, &v, &r);
+
+ if (cmp_type & HY_GLOB) {
+ if (fnmatch(match, r, 0) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+
+ char *vr = pool_tmpjoin(pool, "0-", r, NULL);
+
+ int cmp = pool_evrcmp_str(pool, vr, filter_vr, EVRCMP_COMPARE);
+
+ if ((cmp > 0 && cmp_type & HY_GT) ||
+ (cmp < 0 && cmp_type & HY_LT) ||
+ (cmp == 0 && cmp_type & HY_EQ)) {
+ MAPSET(m, id);
+ }
+ }
+ solv_free(filter_vr);
+ }
+}
+
+void
+Query::Impl::filterArch(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int cmp_type = f.getCmpType();
+ Id match_arch_id = 0;
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+ if (cmp_type & HY_EQ) {
+ match_arch_id = pool_str2id(pool, match, 0);
+ if (match_arch_id == 0)
+ continue;
+ }
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (cmp_type & HY_EQ) {
+ if (match_arch_id == s->arch)
+ MAPSET(m, id);
+ continue;
+ }
+ const char *arch = pool_id2str(pool, s->arch);
+ if (cmp_type & HY_GLOB) {
+ if (fnmatch(match, arch, 0) == 0)
+ MAPSET(m, id);
+ continue;
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterSourcerpm(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+
+ const char *name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
+ if (name == NULL)
+ name = pool_id2str(pool, s->name);
+ if (!g_str_has_prefix(match, name)) // early check
+ continue;
+
+ DnfPackage *pkg = dnf_package_new(sack, id);
+ const char *srcrpm = dnf_package_get_sourcerpm(pkg);
+ if (srcrpm && !strcmp(match, srcrpm))
+ MAPSET(m, id);
+ g_object_unref(pkg);
+ }
+ }
+}
+
+void
+Query::Impl::filterObsoletes(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int obsprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
+ Map *target;
+ auto resultPset = result.get();
+
+ assert(f.getMatchType() == _HY_PKG);
+ assert(f.getMatches().size() == 1);
+ target = dnf_packageset_get_map(f.getMatches()[0].pset);
+ dnf_sack_make_provides_ready(sack);
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (!s->repo)
+ continue;
+ for (Id *r_id = s->repo->idarraydata + s->dep_obsoletes; *r_id; ++r_id) {
+ Id r, rr;
+
+ FOR_PROVIDES(r, rr, *r_id) {
+ if (!MAPTST(target, r))
+ continue;
+ assert(r != SYSTEMSOLVABLE);
+ Solvable *so = pool_id2solvable(pool, r);
+ if (!obsprovides && !pool_match_nevr(pool, so, *r_id))
+ continue; /* only matching pkg names */
+ MAPSET(m, id);
+ break;
+ }
+ }
+ }
+}
+
+void
+Query::Impl::obsoletesByPriority(Pool * pool, Solvable * candidate, Map * m, const Map * target, int obsprovides)
+{
+ if (!candidate->repo)
+ return;
+ for (Id *r_id = candidate->repo->idarraydata + candidate->dep_obsoletes; *r_id; ++r_id) {
+ Id r, rr;
+ FOR_PROVIDES(r, rr, *r_id) {
+ if (!MAPTST(target, r))
+ continue;
+ assert(r != SYSTEMSOLVABLE);
+ Solvable *so = pool_id2solvable(pool, r);
+ if (!obsprovides && !pool_match_nevr(pool, so, *r_id))
+ continue; /* only matching pkg names */
+ MAPSET(m, pool_solvable2id(pool, candidate));
+ break;
+ }
+ }
+}
+
+void
+Query::Impl::filterObsoletesByPriority(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ int obsprovides = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESPROVIDES);
+ Map *target;
+ auto resultPset = result.get();
+
+ assert(f.getMatchType() == _HY_PKG);
+ assert(f.getMatches().size() == 1);
+ target = dnf_packageset_get_map(f.getMatches()[0].pset);
+ dnf_sack_make_provides_ready(sack);
+ std::vector<Solvable *> obsoleteCandidates;
+ obsoleteCandidates.reserve(resultPset->size());
+ Id id = -1;
+ while ((id = resultPset->next(id)) != -1) {
+ Solvable *candidate = pool_id2solvable(pool, id);
+ obsoleteCandidates.push_back(candidate);
+ }
+ if (obsoleteCandidates.empty()) {
+ return;
+ }
+ std::sort(obsoleteCandidates.begin(), obsoleteCandidates.end(), NamePrioritySolvableKey);
+ Id name = 0;
+ int priority = 0;
+ for (auto * candidate: obsoleteCandidates) {
+ if (candidate->repo == pool->installed) {
+ obsoletesByPriority(pool, candidate, m, target, obsprovides);
+ }
+ if (name != candidate->name) {
+ name = candidate->name;
+ priority = candidate->repo->priority;
+ obsoletesByPriority(pool, candidate, m, target, obsprovides);
+ } else if (priority == candidate->repo->priority) {
+ obsoletesByPriority(pool, candidate, m, target, obsprovides);
+ }
+ }
+}
+
+void
+Query::Impl::filterProvidesReldep(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Id p, pp;
+
+ dnf_sack_make_provides_ready(sack);
+ for (auto match_in : f.getMatches()) {
+ Id r_id = match_in.reldep;
+ FOR_PROVIDES(p, pp, r_id)
+ MAPSET(m, p);
+ }
+}
+
+void
+Query::Impl::filterReponame(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Solvable *s;
+ LibsolvRepo *r;
+ Id id;
+ bool ourids[pool->nrepos];
+ auto resultPset = result.get();
+
+ for (id = 0; id < pool->nrepos; ++id)
+ ourids[id] = false;
+ FOR_REPOS(id, r) {
+ for (auto match_in : f.getMatches()) {
+ if (!strcmp(r->name, match_in.str)) {
+ ourids[id] = true;
+ break;
+ }
+ }
+ }
+
+ id = -1;
+ int comparison = f.getCmpType() & ~HY_COMPARISON_FLAG_MASK;
+ if (comparison != HY_EQ)
+ assert(0);
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ s = pool_id2solvable(pool, id);
+ if (s->repo && ourids[s->repo->repoid])
+ MAPSET(m, id);
+ }
+}
+
+void
+Query::Impl::filterLocation(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+
+ const char *location = solvable_get_location(s, NULL);
+ if (location == NULL)
+ continue;
+ if (!strcmp(match, location))
+ MAPSET(m, id);
+ }
+ }
+}
+
+/**
+* @brief Reduce query to security filters. It reflect following compare types: HY_EQ, HY_GT, HY_LT. Additionally it is
+* possible to use HY_EQG. HY_EQG can be combine with HY_UPGRADE or HY_GT. HY_UPGRADE skips advisory that arr already
+* resolved by installed packages. It also select results according priority (important for upgrade-minimal).
+*
+* @param f: Filter that should be applied on advisories
+* @param m: Map of query results complying the filter
+* @param keyname: how are the advisories matched. HY_PKG_ADVISORY, HY_PKG_ADVISORY_BUG,
+* HY_PKG_ADVISORY_CVE, HY_PKG_ADVISORY_TYPE and HY_PKG_ADVISORY_SEVERITY
+* are supported
+*/
+void
+Query::Impl::filterAdvisory(const Filter & f, Map *m, int keyname)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ std::vector<AdvisoryPkg> pkgs;
+ std::vector<AdvisoryPkg> pkgsSecondRun;
+ Dataiterator di;
+ bool eq;
+ auto resultPset = result.get();
+
+ // iterate over advisories
+ dataiterator_init(&di, pool, 0, 0, 0, 0, 0);
+ dataiterator_prepend_keyname(&di, UPDATE_COLLECTION);
+ while (dataiterator_step(&di)) {
+ dataiterator_setpos_parent(&di);
+ Advisory advisory(sack, di.solvid);
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+ switch(keyname) {
+ case HY_PKG_ADVISORY:
+ eq = advisory.matchName(match);
+ break;
+ case HY_PKG_ADVISORY_BUG:
+ eq = advisory.matchBug(match);
+ break;
+ case HY_PKG_ADVISORY_CVE:
+ eq = advisory.matchCVE(match);
+ break;
+ case HY_PKG_ADVISORY_TYPE:
+ eq = advisory.matchKind(match);
+ break;
+ case HY_PKG_ADVISORY_SEVERITY:
+ eq = advisory.matchSeverity(match);
+ break;
+ default:
+ eq = false;
+ }
+ if (eq) {
+ advisory.getApplicablePackages(pkgs, false);
+ break;
+ }
+ }
+ dataiterator_skip_solvable(&di);
+ }
+ dataiterator_free(&di);
+ std::sort(pkgs.begin(), pkgs.end(), advisoryPkgSort);
+
+ int cmp_type = f.getCmpType();
+
+ if (cmp_type & HY_EQG) {
+ std::vector<Solvable *> candidates;
+ std::vector<Solvable *> installed_solvables;
+
+ if (cmp_type & HY_UPGRADE) {
+ // When doing HY_UPGRADE consider only candidate pkgs that:
+ // * have matching Name and Arch with some already installed pkg
+ // (in other words: some other version of the pkg is already installed)
+ // * have matching Name with some already installed pkg and either the candidate or the installed pkg is noarch.
+ // This matches upgrade behavior where we allow architecture change only when noarch is involved.
+ // Details: RhBug:2124483, RhBug:2101398 and RhBug:1171543
+ // * obsoletes some already installed (or to be installed in this transaction) pkg
+ // Otherwise a pkg with different Arch than installed (and than noarch) can end up in upgrade set which is wrong.
+ // It can result in dependency issues, reported as: RhBug:2088149.
+
+ Query installed(sack, ExcludeFlags::IGNORE_EXCLUDES);
+ installed.installed();
+ installed.addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, 1);
+ installed.apply();
+ Id installed_id = -1;
+ while ((installed_id = installed.pImpl->result->next(installed_id)) != -1) {
+ installed_solvables.push_back(pool_id2solvable(pool, installed_id));
+ }
+ std::sort(installed_solvables.begin(), installed_solvables.end(), NameArchSolvableComparator);
+
+ Query obsoletes(sack, ExcludeFlags::IGNORE_EXCLUDES);
+ obsoletes.addFilter(HY_PKG, HY_EQ, resultPset);
+ obsoletes.available();
+
+ Query possibly_obsoleted(sack, ExcludeFlags::IGNORE_EXCLUDES);
+ possibly_obsoleted.addFilter(HY_PKG, HY_EQ, resultPset);
+ possibly_obsoleted.addFilter(HY_PKG_UPGRADES, HY_EQ, 1);
+ possibly_obsoleted.queryUnion(installed);
+ possibly_obsoleted.apply();
+
+ obsoletes.addFilter(HY_PKG_OBSOLETES, HY_EQ, possibly_obsoleted.runSet());
+ obsoletes.apply();
+ Id obsoleted_id = -1;
+ // Add to candidates resultPset pkgs that obsolete some installed (or to be installed in this transaction) pkg
+ while ((obsoleted_id = obsoletes.pImpl->result->next(obsoleted_id)) != -1) {
+ Solvable * s = pool_id2solvable(pool, obsoleted_id);
+ candidates.push_back(s);
+ }
+
+ Id id = -1;
+ // Add to candidates resultPset pkgs that match name and arch with some already installed pkg or match name and either the installed or candidate are NOARCH
+ while ((id = resultPset->next(id)) != -1) {
+ Solvable * s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(installed_solvables.begin(), installed_solvables.end(), s, NameSolvableComparator);
+ while (low != installed_solvables.end() && (*low)->name == s->name) {
+ if (s->arch == (*low)->arch || s->arch == ARCH_NOARCH || (*low)->arch == ARCH_NOARCH) {
+ candidates.push_back(s);
+ break;
+ }
+ ++low;
+ }
+ }
+
+ // Apply security filters only to packages with lower priority - to unify behaviour upgrade
+ // and upgrade-minimal
+ std::sort(candidates.begin(), candidates.end(), NameArchPrioritySolvableKey);
+ std::vector<Solvable *> priority_candidates;
+ Id name = 0;
+ Id arch = 0;
+ int priority = 0;
+
+ for (auto * candidate: candidates) {
+ if (candidate->repo == pool->installed) {
+ priority_candidates.push_back(candidate);
+ } else if (name != candidate->name || arch != candidate->arch) {
+ name = candidate->name;
+ arch = candidate->arch;
+ priority = candidate->repo->priority;
+ priority_candidates.push_back(candidate);
+ } else if (priority == candidate->repo->priority) {
+ priority_candidates.push_back(candidate);
+ }
+ }
+ std::swap(candidates, priority_candidates);
+ } else {
+ Id id = -1;
+ while ((id = resultPset->next(id)) != -1) {
+ candidates.push_back(pool_id2solvable(pool, id));
+ }
+ }
+
+ NameArchEVRComparator cmp_key(pool);
+ std::sort(candidates.begin(), candidates.end(), cmp_key);
+ for (auto & advisoryPkg : pkgs) {
+ if (cmp_type & HY_UPGRADE) {
+ // skip advisory pkgs that have lower evr than installed version - important for upgrade logic
+ auto low = std::lower_bound(installed_solvables.begin(), installed_solvables.end(), advisoryPkg, SolvableCompareAdvisoryPkgNameArch);
+ if (low != installed_solvables.end() && advisoryPkg.getName() == (*low)->name && advisoryPkg.getArch() == (*low)->arch) {
+ // Skip all advisory packages that has same or lover ever than installed
+ if (pool_evrcmp(pool, (*low)->evr, advisoryPkg.getEVR(), EVRCMP_COMPARE) >= 0) {
+ continue;
+ }
+ }
+ }
+ auto low = std::lower_bound(candidates.begin(), candidates.end(), advisoryPkg, cmp_key);
+ if (low != candidates.end() && advisoryPkg.getName() == (*low)->name && advisoryPkg.getArch() == (*low)->arch) {
+ MAPSET(m, pool_solvable2id(pool, (*low)));
+ if (cmp_type & HY_GT) {
+ ++low;
+ while (low != candidates.end() && advisoryPkg.getName() == (*low)->name && advisoryPkg.getArch() == (*low)->arch) {
+ MAPSET(m, pool_solvable2id(pool, (*low)));
+ ++low;
+ }
+ }
+ }
+ }
+ } else {
+ // convert nevras (from DnfAdvisoryPkg) to pool ids
+ Id id = -1;
+ while (true) {
+ if (pkgs.size() == 0)
+ break;
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ if (cmp_type == HY_EQ) {
+ auto low = std::lower_bound(pkgs.begin(), pkgs.end(), *s, advisoryPkgCompareSolvable);
+ if (low != pkgs.end() && low->nevraEQ(s)) {
+ MAPSET(m, id);
+ }
+ } else {
+ auto low = std::lower_bound(pkgs.begin(), pkgs.end(), *s, advisoryPkgCompareSolvableNameArch);
+ while (low != pkgs.end() && low->getName() == s->name && low->getArch() == s->arch) {
+ int cmp = pool_evrcmp(pool, s->evr, low->getEVR(), EVRCMP_COMPARE);
+ if ((cmp > 0 && cmp_type & HY_GT) ||
+ (cmp < 0 && cmp_type & HY_LT) ||
+ (cmp == 0 && cmp_type & HY_EQ)) {
+ MAPSET(m, id);
+ break;
+ }
+ ++low;
+ }
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterLatest(const Filter & f, Map *m)
+{
+ int keyname = f.getKeyname();
+ Pool *pool = dnf_sack_get_pool(sack);
+ auto resultPset = result.get();
+
+ for (auto match_in : f.getMatches()) {
+ int latest = match_in.num;
+ if (latest == 0)
+ continue;
+ Queue samename;
+
+ queue_init(&samename);
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ queue_push(&samename, id);
+ }
+
+ if (keyname == HY_PKG_LATEST_PER_ARCH) {
+ solv_sort(samename.elements, samename.count, sizeof(Id),
+ filter_latest_sortcmp_byarch, pool);
+ } else if (keyname == HY_PKG_LATEST_PER_ARCH_BY_PRIORITY) {
+ solv_sort(samename.elements, samename.count, sizeof(Id),
+ filter_latest_sortcmp_byarch_bypriority, pool);
+ } else {
+ solv_sort(samename.elements, samename.count, sizeof(Id),
+ filter_latest_sortcmp, pool);
+ }
+
+ // Create blocks per name, arch and repo priority
+ // But call add_latest_to_map only for the block with highest priority
+ Solvable *considered, *highest = 0;
+ bool make_block = 1;
+ int start_block = -1;
+ int i;
+ for (i = 0; i < samename.count; ++i) {
+ Id p = samename.elements[i];
+ considered = pool->solvables + p;
+ if (!highest ||
+ highest->name != considered->name ||
+ ((keyname == HY_PKG_LATEST_PER_ARCH || keyname == HY_PKG_LATEST_PER_ARCH_BY_PRIORITY) &&
+ highest->arch != considered->arch)) {
+ /* start of a new block */
+ if (start_block == -1) {
+ highest = considered;
+ start_block = i;
+ continue;
+ }
+ if (make_block) {
+ add_latest_to_map(pool, m, &samename, start_block, i, latest);
+ }
+ else {
+ make_block = 1;
+ }
+ highest = considered;
+ start_block = i;
+ } else if (keyname == HY_PKG_LATEST_PER_ARCH_BY_PRIORITY &&
+ highest->repo->priority != considered->repo->priority &&
+ make_block) {
+ add_latest_to_map(pool, m, &samename, start_block, i, latest);
+ make_block = 0;
+ }
+ }
+ if (start_block != -1 && make_block) { // Add last block to the map
+ add_latest_to_map(pool, m, &samename, start_block, i, latest);
+ }
+ queue_free(&samename);
+ }
+}
+
+void
+Query::Impl::filterUpdown(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ auto resultPset = result.get();
+
+ dnf_sack_make_provides_ready(sack);
+
+ if (!pool->installed) {
+ return;
+ }
+
+ for (auto match_in : f.getMatches()) {
+ if (match_in.num == 0)
+ continue;
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable *s = pool_id2solvable(pool, id);
+ if (s->repo == pool->installed)
+ continue;
+ if (f.getKeyname() == HY_PKG_DOWNGRADES) {
+ if (what_downgrades(pool, id) > 0)
+ MAPSET(m, id);
+ } else if (what_upgrades(pool, id) > 0)
+ MAPSET(m, id);
+ }
+ }
+}
+
+void
+Query::Impl::filterUpdownByPriority(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ auto resultPset = result.get();
+
+ dnf_sack_make_provides_ready(sack);
+ auto repoInstalled = pool->installed;
+ if (!repoInstalled) {
+ return;
+ }
+
+ for (auto match_in : f.getMatches()) {
+ if (match_in.num == 0)
+ continue;
+ std::vector<Solvable *> upgradeCandidates;
+ upgradeCandidates.reserve(resultPset->size());
+ Id id = -1;
+ while ((id = resultPset->next(id)) != -1) {
+ Solvable *candidate = pool_id2solvable(pool, id);
+ if (candidate->repo == repoInstalled)
+ continue;
+ upgradeCandidates.push_back(candidate);
+ }
+ if (upgradeCandidates.empty()) {
+ continue;
+ }
+ std::sort(upgradeCandidates.begin(), upgradeCandidates.end(), NamePrioritySolvableKey);
+ Id name = 0;
+ int priority = 0;
+ for (auto * candidate: upgradeCandidates) {
+ if (name != candidate->name) {
+ name = candidate->name;
+ priority = candidate->repo->priority;
+ id = pool_solvable2id(pool, candidate);
+ if (what_upgrades(pool, id) > 0) {
+ MAPSET(m, id);
+ }
+ } else if (priority == candidate->repo->priority) {
+ id = pool_solvable2id(pool, candidate);
+ if (what_upgrades(pool, id) > 0) {
+ MAPSET(m, id);
+ }
+ }
+ }
+ }
+}
+
+void
+Query::Impl::filterUpdownAble(const Filter &f, Map *m)
+{
+ Id p, what;
+ Solvable *s;
+ Pool *pool = dnf_sack_get_pool(sack);
+
+ dnf_sack_make_provides_ready(sack);
+
+ if (!pool->installed) {
+ return;
+ }
+ auto resultMap = result->getMap();
+
+ for (auto match_in : f.getMatches()) {
+ if (match_in.num == 0)
+ continue;
+
+ FOR_PKG_SOLVABLES(p) {
+ if (flags == Query::ExcludeFlags::APPLY_EXCLUDES) {
+ if (pool->considered && !map_tst(pool->considered, p))
+ continue;
+ } else {
+ if (considered_cached && !map_tst(considered_cached, p))
+ continue;
+ }
+ s = pool_id2solvable(pool, p);
+ if (s->repo == pool->installed)
+ continue;
+
+ what = (f.getKeyname() == HY_PKG_DOWNGRADABLE) ? what_downgrades(pool, p) :
+ what_upgrades(pool, p);
+ if (what != 0 && map_tst(resultMap, what))
+ map_set(m, what);
+ }
+ }
+}
+
+void
+Query::Impl::filterDataiterator(const Filter & f, Map *m)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Dataiterator di;
+ Id keyname = di_keyname2id(f.getKeyname());
+ int flags = type2flags(f.getCmpType(), f.getKeyname());
+ auto resultPset = result.get();
+
+ assert(f.getMatchType() == _HY_STR);
+
+ for (auto match_in : f.getMatches()) {
+ const char *match = match_in.str;
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ dataiterator_init(&di, pool, 0, id, keyname, match, flags);
+ while (dataiterator_step(&di)) {
+ MAPSET(m, id);
+ break;
+ }
+ dataiterator_free(&di);
+ }
+ }
+}
+
+int
+Query::Impl::filterUnneededOrSafeToRemove(const Swdb &swdb, bool debug_solver, bool safeToRemove)
+{
+ apply();
+ Goal goal(sack);
+ Pool *pool = dnf_sack_get_pool(sack);
+ Query installed(sack);
+ installed.installed();
+ auto userInstalled = installed.getResultPset();
+
+ swdb.filterUserinstalled(*userInstalled);
+ if (safeToRemove) {
+ *userInstalled -= *result;
+ }
+ goal.userInstalled(*userInstalled);
+
+ int ret1 = goal.run(DNF_NONE);
+ if (ret1)
+ return -1;
+
+ if (debug_solver) {
+ g_autoptr(GError) error = NULL;
+ gboolean ret = hy_goal_write_debugdata(&goal, "./debugdata-autoremove", &error);
+ if (!ret) {
+ return -1;
+ }
+ }
+
+ IdQueue que;
+ Solver *solv = goal.pImpl->solv;
+
+ solver_get_unneeded(solv, que.getQueue(), 0);
+ Map resultInternal;
+ map_init(&resultInternal, pool->nsolvables);
+
+ for (int i = 0; i < que.size(); ++i) {
+ MAPSET(&resultInternal, que[i]);
+ }
+ map_and(result->getMap(), &resultInternal);
+ map_free(&resultInternal);
+ return 0;
+}
+
+bool Query::Impl::isGlob(const std::vector<const char *> &matches) const
+{
+ for (const char *match : matches) {
+ if (hy_is_glob_pattern(match)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+Query::apply() { pImpl->apply(); }
+
+void
+Query::Impl::apply()
+{
+ if (applied)
+ return;
+
+ Pool *pool = dnf_sack_get_pool(sack);
+ repo_internalize_all_trigger(pool);
+ Map m;
+ if (!result)
+ initResult();
+ map_init(&m, pool->nsolvables);
+ map_grow(result->getMap(), pool->nsolvables);
+ for (auto f : filters) {
+ map_empty(&m);
+ switch (f.getKeyname()) {
+ case HY_PKG:
+ filterPkg(f, &m);
+ break;
+ case HY_PKG_ALL:
+ case HY_PKG_EMPTY:
+ /* used to set query empty by keeping Map m empty */
+ break;
+ case HY_PKG_NAME:
+ filterName(f, &m);
+ break;
+ case HY_PKG_EPOCH:
+ filterEpoch(f, &m);
+ break;
+ case HY_PKG_EVR:
+ filterEvr(f, &m);
+ break;
+ case HY_PKG_NEVRA:
+ filterNevra(f, &m);
+ break;
+ case HY_PKG_VERSION:
+ filterVersion(f, &m);
+ break;
+ case HY_PKG_RELEASE:
+ filterRelease(f, &m);
+ break;
+ case HY_PKG_ARCH:
+ filterArch(f, &m);
+ break;
+ case HY_PKG_SOURCERPM:
+ filterSourcerpm(f, &m);
+ break;
+ case HY_PKG_OBSOLETES:
+ if (f.getMatchType() == _HY_RELDEP)
+ filterRcoReldep(f, &m);
+ else {
+ assert(f.getMatchType() == _HY_PKG);
+ filterObsoletes(f, &m);
+ }
+ break;
+ case HY_PKG_OBSOLETES_BY_PRIORITY:
+ filterObsoletesByPriority(f, &m);
+ break;
+ case HY_PKG_PROVIDES:
+ assert(f.getMatchType() == _HY_RELDEP);
+ filterProvidesReldep(f, &m);
+ break;
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUPPLEMENTS:
+ if (f.getMatchType() == _HY_RELDEP)
+ filterRcoReldep(f, &m);
+ else {
+ filterDepSolvable(f, &m);
+ }
+ break;
+ case HY_PKG_REPONAME:
+ filterReponame(f, &m);
+ break;
+ case HY_PKG_LOCATION:
+ filterLocation(f, &m);
+ break;
+ case HY_PKG_ADVISORY:
+ case HY_PKG_ADVISORY_BUG:
+ case HY_PKG_ADVISORY_CVE:
+ case HY_PKG_ADVISORY_SEVERITY:
+ case HY_PKG_ADVISORY_TYPE:
+ filterAdvisory(f, &m, f.getKeyname());
+ break;
+ case HY_PKG_LATEST:
+ case HY_PKG_LATEST_PER_ARCH:
+ case HY_PKG_LATEST_PER_ARCH_BY_PRIORITY:
+ filterLatest(f, &m);
+ break;
+ case HY_PKG_DOWNGRADABLE:
+ case HY_PKG_UPGRADABLE:
+ filterUpdownAble(f, &m);
+ break;
+ case HY_PKG_DOWNGRADES:
+ case HY_PKG_UPGRADES:
+ filterUpdown(f, &m);
+ break;
+ case HY_PKG_UPGRADES_BY_PRIORITY:
+ filterUpdownByPriority(f, &m);
+ break;
+ default:
+ filterDataiterator(f, &m);
+ }
+ if (f.getCmpType() & HY_NOT)
+ map_subtract(result->getMap(), &m);
+ else
+ map_and(result->getMap(), &m);
+ }
+ map_free(&m);
+
+ applied = true;
+ filters.clear();
+}
+
+GPtrArray *
+Query::run()
+{
+ pImpl->apply();
+ return packageSet2GPtrArray(pImpl->result.get());
+}
+
+const DnfPackageSet *
+Query::runSet()
+{
+ apply();
+ return pImpl->result.get();
+}
+
+Id
+Query::getIndexItem(int index)
+{
+ apply();
+ return (*pImpl->result.get())[index];
+}
+
+void
+Query::queryUnion(Query & other)
+{
+ apply();
+ other.apply();
+ *(pImpl->result.get()) += *(other.pImpl->result.get());
+}
+
+void
+Query::queryIntersection(Query & other)
+{
+ apply();
+ other.apply();
+ *(pImpl->result.get()) /= *(other.pImpl->result.get());
+}
+
+void
+Query::queryDifference(Query & other)
+{
+ apply();
+ other.apply();
+ *(pImpl->result.get()) -= *(other.pImpl->result.get());
+}
+
+bool
+Query::empty()
+{
+ apply();
+ return pImpl->result->empty();
+}
+
+void
+Query::filterExtras()
+{
+ apply();
+
+ Pool * pool = dnf_sack_get_pool(pImpl->sack);
+
+ auto resultMap = pImpl->result->getMap();
+ Query query_installed(*this);
+ query_installed.installed();
+ MAPZERO(resultMap);
+ if (query_installed.size() == 0) {
+ return;
+ }
+
+ // create query with available packages without non-modular excludes. As a extras should be
+ // considered anso packages in non-active modules
+ Query query_available(pImpl->sack, Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES);
+ query_available.available();
+
+ auto resultAvailable = query_available.pImpl->result.get();
+ Id id_available = -1;
+
+ // make vector of available solvables
+ std::vector<Solvable *> namesArch;
+ namesArch.reserve(resultAvailable->size());
+ while ((id_available = resultAvailable->next(id_available)) != -1) {
+ namesArch.push_back(pool_id2solvable(pool, id_available));
+ }
+ std::sort(namesArch.begin(), namesArch.end(), NameArchSolvableComparator);
+ Id id_installed = -1;
+ auto resultInstalled = query_installed.pImpl->result.get();
+
+ while ((id_installed = resultInstalled->next(id_installed)) != -1) {
+ Solvable * s_installed = pool_id2solvable(pool, id_installed);
+ auto low = std::lower_bound(namesArch.begin(), namesArch.end(), s_installed,
+ NameArchSolvableComparator);
+ if (low == namesArch.end() || (*low)->name != s_installed->name ||
+ (*low)->arch != s_installed->arch) {
+ MAPSET(resultMap, id_installed);
+ }
+ }
+}
+
+void
+Query::filterRecent(const long unsigned int recent_limit)
+{
+ apply();
+ auto resultPset = pImpl->result.get();
+ auto resultMap = pImpl->result->getMap();
+
+ Id id = -1;
+ while (true) {
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ DnfPackage *pkg = dnf_package_new(pImpl->sack, id);
+ guint64 build_time = dnf_package_get_buildtime(pkg);
+ g_object_unref(pkg);
+ if (build_time <= recent_limit) {
+ MAPCLR(resultMap, id);
+ }
+ }
+}
+
+void
+Query::filterDuplicated()
+{
+ IdQueue samename;
+ Pool *pool = dnf_sack_get_pool(pImpl->sack);
+
+ installed();
+
+ auto resultMap = pImpl->result->getMap();
+ hy_query_to_name_ordered_queue(this, &samename);
+
+ Solvable *considered, *highest = 0;
+ int start_block = -1;
+ int i;
+ MAPZERO(resultMap);
+ for (i = 0; i < samename.size(); ++i) {
+ Id p = samename[i];
+ considered = pool->solvables + p;
+ if (!highest || highest->name != considered->name) {
+ /* start of a new block */
+ if (start_block == -1) {
+ highest = considered;
+ start_block = i;
+ continue;
+ }
+ if (start_block != i - 1) {
+ add_duplicates_to_map(pool, resultMap, samename, start_block, i);
+ }
+ highest = considered;
+ start_block = i;
+ }
+ }
+ if (start_block != -1) {
+ add_duplicates_to_map(pool, resultMap, samename, start_block, i);
+ }
+}
+
+int
+Query::filterUnneeded(const Swdb &swdb, bool debug_solver)
+{
+ return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, false);
+}
+
+int
+Query::filterSafeToRemove(const Swdb &swdb, bool debug_solver)
+{
+ return pImpl->filterUnneededOrSafeToRemove(swdb, debug_solver, true);
+}
+
+void
+Query::getAdvisoryPkgs(int cmpType, std::vector<AdvisoryPkg> & advisoryPkgs)
+{
+ apply();
+ auto sack = pImpl->sack;
+ Pool *pool = dnf_sack_get_pool(sack);
+ std::vector<AdvisoryPkg> pkgs;
+ Dataiterator di;
+ auto resultPset = pImpl->result.get();
+
+ // iterate over advisories
+ dataiterator_init(&di, pool, 0, 0, 0, 0, 0);
+ dataiterator_prepend_keyname(&di, UPDATE_COLLECTION);
+ while (dataiterator_step(&di)) {
+ Advisory advisory(sack, di.solvid);
+ advisory.getApplicablePackages(pkgs);
+ dataiterator_skip_solvable(&di);
+ }
+ dataiterator_free(&di);
+ std::sort(pkgs.begin(), pkgs.end(), advisoryPkgSort);
+ // convert nevras (from DnfAdvisoryPkg) to pool ids
+ Id id = -1;
+ while (true) {
+ if (pkgs.size() == 0)
+ break;
+ id = resultPset->next(id);
+ if (id == -1)
+ break;
+ Solvable* s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(pkgs.begin(), pkgs.end(), *s,
+ advisoryPkgCompareSolvableNameArch);
+ while (low != pkgs.end() && low->getName() == s->name && low->getArch() == s->arch) {
+ int cmp = pool_evrcmp(pool, low->getEVR(), s->evr, EVRCMP_COMPARE);
+ if ((cmp > 0 && cmpType & HY_GT) ||
+ (cmp < 0 && cmpType & HY_LT) ||
+ (cmp == 0 && cmpType & HY_EQ)) {
+ advisoryPkgs.push_back(*low);
+ }
+ ++low;
+ }
+ }
+}
+
+std::set<std::string> Query::getStringsFromProvide(const char * patternProvide)
+{
+ DnfSack * sack = getSack();
+ auto queryResult = runSet();
+ Id pkgId = -1;
+ size_t lenPatternProvide = strlen(patternProvide);
+ std::set<std::string> result;
+ while ((pkgId = queryResult->next(pkgId)) != -1) {
+ std::unique_ptr<DnfPackage> pkg(dnf_package_new(sack, pkgId));
+ std::unique_ptr<DnfReldepList> provides(dnf_package_get_provides(pkg.get()));
+ auto count = provides->count();
+ for (int index = 0; index < count; ++index) {
+ Dependency provide(sack, provides->getId(index));
+ auto provideName = provide.getName();
+ size_t lenProvide = strlen(provideName);
+ if (lenProvide > lenPatternProvide + 2
+ && strncmp(patternProvide, provideName, lenPatternProvide) == 0
+ && provideName[lenPatternProvide] == '('
+ && provideName[lenProvide - 1] == ')') {
+ result.emplace(
+ provideName + lenPatternProvide + 1, lenProvide - lenPatternProvide - 2);
+ }
+ }
+ }
+ return result;
+}
+
+void
+Query::filterUserInstalled(const Swdb &swdb)
+{
+ installed();
+ swdb.filterUserinstalled(*getResultPset());
+}
+
+void
+Query::installed()
+{
+ apply();
+ Pool * pool = dnf_sack_get_pool(pImpl->sack);
+ auto * installed_repo = pool->installed;
+ auto queryResult = pImpl->result.get();
+ if (installed_repo == nullptr) {
+ queryResult->clear();
+ return;
+ }
+ Map filterResult;
+ map_init(&filterResult, pool->nsolvables);
+ Id pkgId = installed_repo->start;
+ if (!queryResult->has(pkgId)) {
+ pkgId = queryResult->next(pkgId);
+ }
+ for (; pkgId != -1; pkgId = queryResult->next(pkgId)) {
+ Solvable * solvable = pool_id2solvable(pool, pkgId);
+ if (solvable->repo == installed_repo) {
+ MAPSET(&filterResult, pkgId);
+ continue;
+ }
+ if (pkgId < installed_repo->end) {
+ continue;
+ }
+ break;
+ }
+ map_and(queryResult->getMap(), &filterResult);
+ map_free(&filterResult);
+}
+
+void
+Query::available()
+{
+ apply();
+ Pool * pool = dnf_sack_get_pool(pImpl->sack);
+ auto * installed_repo = pool->installed;
+ if (installed_repo == nullptr) {
+ return;
+ }
+ auto queryResult = pImpl->result.get();
+ Id pkgId = installed_repo->start;
+ if (!queryResult->has(pkgId)) {
+ pkgId = queryResult->next(pkgId);
+ }
+ for (; pkgId != -1; pkgId = queryResult->next(pkgId)) {
+ Solvable * solvable = pool_id2solvable(pool, pkgId);
+ if (solvable->repo == installed_repo) {
+ queryResult->remove(pkgId);
+ continue;
+ }
+ if (pkgId < installed_repo->end) {
+ continue;
+ }
+ break;
+ }
+}
+
+std::pair<bool, std::unique_ptr<Nevra>>
+Query::filterSubject(const char * subject, HyForm * forms, bool icase, bool with_nevra,
+ bool with_provides, bool with_filenames)
+{
+ apply();
+ Query origQuery(*this);
+
+ if (with_nevra) {
+ Nevra nevraObj;
+ const HyForm * tryForms = !forms ? HY_FORMS_MOST_SPEC : forms;
+ for (std::size_t i = 0; tryForms[i] != _HY_FORM_STOP_; ++i) {
+ if (nevraObj.parse(subject, tryForms[i])) {
+ addFilter(&nevraObj, icase);
+ if (!empty()) {
+ return {true, std::unique_ptr<Nevra>(new Nevra(std::move(nevraObj)))};
+ }
+ queryUnion(origQuery);
+ }
+ }
+ if (!forms) {
+ queryUnion(origQuery);
+ addFilter(HY_PKG_NEVRA, HY_GLOB, subject);
+ if (!empty()) {
+ return {true, std::unique_ptr<Nevra>()};
+ }
+ }
+ }
+
+ if (with_provides) {
+ queryUnion(origQuery);
+ addFilter(HY_PKG_PROVIDES, HY_GLOB, subject);
+ if (!empty()) {
+ return {true, std::unique_ptr<Nevra>()};
+ }
+ }
+
+ if (with_filenames && hy_is_file_pattern(subject)) {
+ queryUnion(origQuery);
+ addFilter(HY_PKG_FILE, HY_GLOB, subject);
+ if (!empty()) {
+ return {true, std::unique_ptr<Nevra>()};
+ }
+ }
+
+ addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+ return {false, std::unique_ptr<Nevra>()};
+}
+
+void
+hy_query_to_name_ordered_queue(HyQuery query, IdQueue * samename)
+{
+ hy_query_apply(query);
+ Pool *pool = dnf_sack_get_pool(query->getSack());
+
+ const auto result = query->getResult();
+ for (int i = 1; i < pool->nsolvables; ++i)
+ if (MAPTST(result, i))
+ samename->pushBack(i);
+
+ solv_sort(samename->data(), samename->size(), sizeof(Id), filter_latest_sortcmp,
+ pool);
+}
+
+void
+hy_query_to_name_arch_ordered_queue(HyQuery query, IdQueue * samename)
+{
+ hy_query_apply(query);
+ Pool *pool = dnf_sack_get_pool(query->getSack());
+
+ const auto result = query->getResult();
+ for (int i = 1; i < pool->nsolvables; ++i)
+ if (MAPTST(result, i))
+ samename->pushBack(i);
+
+ solv_sort(samename->data(), samename->size(), sizeof(Id),
+ filter_latest_sortcmp_byarch, pool);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __QUERY_HPP
+#define __QUERY_HPP
+
+#include <memory>
+#include <vector>
+#include "../hy-types.h"
+#include "../hy-query.h"
+#include "../hy-subject.h"
+#include "../nevra.hpp"
+#include "../repo/solvable/Dependency.hpp"
+#include "../repo/solvable/DependencyContainer.hpp"
+#include "../transaction/Swdb.hpp"
+#include "../dnf-types.h"
+#include "advisorypkg.hpp"
+
+#include <set>
+#include <utility>
+
+namespace libdnf {
+
+union _Match {
+ int num;
+ DnfPackageSet *pset;
+ Id reldep;
+ char *str;
+};
+
+struct Filter {
+public:
+ Filter(int keyname, int cmp_type, int match);
+ Filter(int keyname, int cmp_type, int nmatches, const int *matches);
+ Filter(int keyname, int cmp_type, const DnfPackageSet * pset);
+ Filter(int keyname, int cmp_type, const Dependency * reldep);
+ Filter(int keyname, int cmp_type, const DependencyContainer * reldeplist);
+ Filter(int keyname, int cmp_type, const char *match);
+ Filter(int keyname, int cmp_type, const char **matches);
+ Filter(_hy_key_name_e keyname, int comparisonType, const std::vector<const char *> &matches);
+ ~Filter();
+ int getKeyname() const noexcept;
+ int getCmpType() const noexcept;
+ int getMatchType() const noexcept;
+ const std::vector<_Match> & getMatches() const noexcept;
+private:
+ class Impl;
+ std::shared_ptr<Impl> pImpl;
+};
+
+/**
+* @brief Provides package filtering
+* addFilter() can return DNF_ERROR_BAD_QUERY in case if cmp_type or keyname is incompatible with provided data type
+*
+*/
+struct Query {
+public:
+ enum class ExcludeFlags {
+ APPLY_EXCLUDES = 0,
+ IGNORE_MODULAR_EXCLUDES = 1 << 0,
+ IGNORE_REGULAR_EXCLUDES = 1 << 1,
+ IGNORE_EXCLUDES = IGNORE_MODULAR_EXCLUDES | IGNORE_REGULAR_EXCLUDES
+ };
+
+ Query(const Query & query_src);
+ Query(Query && query_src) = delete;
+ Query(DnfSack* sack, ExcludeFlags flags = ExcludeFlags::APPLY_EXCLUDES);
+ ~Query();
+ Query & operator=(const Query& query_src);
+ Query & operator=(Query && src_query) = delete;
+ Map * getResult() noexcept;
+ const Map * getResult() const noexcept;
+ /**
+ * @brief Applies query and returns pointer of PackageSet
+ *
+ * @return PackageSet*
+ */
+ PackageSet * getResultPset();
+ DnfSack * getSack();
+
+ /**
+ * @brief Return true if query was previously applied
+ *
+ * @return bool
+ */
+ bool getApplied() const noexcept;
+
+ /**
+ * @brief Remove all filters and reset the result
+ *
+ */
+ void clear();
+
+ /**
+ * @brief Applies Query and retuns count of packages
+ *
+ * @return size_t
+ */
+ size_t size();
+ int addFilter(int keyname, int cmp_type, int match);
+ int addFilter(int keyname, int cmp_type, int nmatches, const int *matches);
+ int addFilter(int keyname, int cmp_type, const DnfPackageSet *pset);
+ int addFilter(int keyname, const Dependency * reldep);
+ int addFilter(int keyname, const DependencyContainer * reldeplist);
+ int addFilter(int keyname, int cmp_type, const char *match);
+ int addFilter(int keyname, int cmp_type, const char **matches);
+ int addFilter(_hy_key_name_e keyname, _hy_comparison_type_e comparisonType, const std::vector<const char *> &matches);
+ int addFilter(HyNevra nevra, bool icase);
+ void apply();
+
+ /**
+ * @brief Applies Query and returns DnfPackages in GPtrArray
+ *
+ * @return GPtrArray*
+ */
+ GPtrArray * run();
+
+ /**
+ * @brief Applies Query and returns result in DnfPackageSet
+ *
+ * @return DnfPackageSet*
+ */
+ const DnfPackageSet * runSet();
+ Id getIndexItem(int index);
+
+ /**
+ * @brief Applies both queries and result of the other query is added to result of this query
+ *
+ * @param other p_other:...
+ */
+ void queryUnion(Query & other);
+
+ /**
+ * @brief Applies both queries and keep only common packages for both queries in this query
+ *
+ * @param other p_other:...
+ */
+ void queryIntersection(Query & other);
+
+ /**
+ * @brief Applies both queries and keep only packages in this query that are absent in other query
+ *
+ * @param other p_other:...
+ */
+ void queryDifference(Query & other);
+
+ /**
+ * @brief Applies Query and returns true if any package in the query
+ *
+ * @return bool
+ */
+ bool empty();
+ /**
+ * @brief Applies all filters and keep only installed packages that have no available package
+ * with a same name and architecture.
+ * Excluded available packages are handled like other available packages. Modular excludes are
+ * applied.
+ */
+ void filterExtras();
+ void filterRecent(const long unsigned int recent_limit);
+ void filterDuplicated();
+ int filterUnneeded(const Swdb &swdb, bool debug_solver);
+ int filterSafeToRemove(const Swdb &swdb, bool debug_solver);
+ void getAdvisoryPkgs(int cmpType, std::vector<AdvisoryPkg> & advisoryPkgs);
+ void filterUserInstalled(const Swdb &swdb);
+ /**
+ * @brief Applies all filters and keep only installed packages
+ */
+ void installed();
+ /**
+ * @brief Applies all filters and keep only available packages
+ */
+ void available();
+
+ /**
+ * @brief Apply query and return a set of strings representing information in provide that begin
+ * by patternProvide. For pattern "base-platform" and presence of provide
+ * "base-platform(platform:f26)", the function will return "platform:f26" in set.
+ *
+ * @param patternProvide p_patternProvide: No glob allowed!
+ * @return std::set< std::__cxx11::string >
+ */
+ std::set<std::string> getStringsFromProvide(const char * patternProvide);
+
+ /**
+ * @brief Filter packages to match a given subject
+ *
+ * @param subject an subject to match
+ * @param forms an array of pattern forms, nullptr means a default forms are used, used only for search with_nevra
+ * @param icase true - matches the subject without sensitivity to case
+ * @param with_nevra true - enable search by nevra
+ * @param with_provides true - provides are searched for a match
+ * @param with_filenames true - file provides are searched for a match
+ *
+ * @return std::pair<bool, std::unique_ptr<Nevra>> The bool is denoting whether there are matched packages.
+ * The Nevra is denoting used pattern form to match. It is nullptr, if with_nevra search
+ * was not used or there is no package whose Nevra would match to the subject.
+ */
+ std::pair<bool, std::unique_ptr<Nevra>> filterSubject(const char * subject, HyForm * forms,
+ bool icase, bool with_nevra, bool with_provides, bool with_filenames);
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+inline Query::ExcludeFlags operator|(Query::ExcludeFlags a, Query::ExcludeFlags b)
+{
+ return static_cast<Query::ExcludeFlags>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline Query::ExcludeFlags operator&(Query::ExcludeFlags a, Query::ExcludeFlags b)
+{
+ return static_cast<Query::ExcludeFlags>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+}
+
+#endif /* __QUERY_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <solv/selection.h>
+#include <solv/solver.h>
+#include <solv/util.h>
+
+#include "../dnf-sack-private.hpp"
+#include "../dnf-types.h"
+#include "../hy-goal-private.hpp"
+#include "../hy-iutil.h"
+#include "../hy-package-private.hpp"
+#include "../hy-query-private.hpp"
+#include "../hy-selector-private.hpp"
+#include "../hy-util-private.hpp"
+#include "../repo/solvable/Dependency.hpp"
+
+namespace libdnf {
+
+static bool
+valid_setting(int keyname, int cmp_type)
+{
+ switch (keyname) {
+ case HY_PKG_ARCH:
+ case HY_PKG_EVR:
+ case HY_PKG_REPONAME:
+ case HY_PKG_VERSION:
+ return cmp_type == HY_EQ;
+ case HY_PKG_PROVIDES:
+ case HY_PKG_NAME:
+ return cmp_type == HY_EQ || cmp_type == HY_GLOB;
+ case HY_PKG_FILE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+class Selector::Impl {
+public:
+ DnfSack * sack;
+ std::unique_ptr<Filter> filterArch;
+ std::unique_ptr<Filter> filterEvr;
+ std::unique_ptr<Filter> filterFile;
+ std::unique_ptr<Filter> filterName;
+ /**
+ * @brief Set pkgs created by pool_queuetowhatprovides
+ */
+ Id pkgs{0};
+ std::unique_ptr<Filter> filterProvides;
+ std::unique_ptr<Filter> filterReponame;
+private:
+ friend struct Selector;
+ std::vector<_Match> matches;
+};
+
+Selector::Selector(DnfSack* sack) : pImpl(new Impl) { pImpl->sack = sack; }
+
+Selector::Selector(Selector && src)
+{
+ pImpl = std::move(src.pImpl);
+ src.pImpl.reset(new Impl);
+ src.pImpl->sack = pImpl->sack;
+}
+
+Selector::~Selector() = default;
+
+DnfSack *Selector::getSack() { return pImpl->sack; }
+const Filter *Selector::getFilterArch() const { return pImpl->filterArch.get(); }
+const Filter *Selector::getFilterEvr() const { return pImpl->filterEvr.get(); }
+const Filter *Selector::getFilterFile() const { return pImpl->filterFile.get(); }
+const Filter *Selector::getFilterName() const { return pImpl->filterName.get(); }
+Id Selector::getPkgs() const { return pImpl->pkgs; }
+const Filter *Selector::getFilterProvides() const { return pImpl->filterProvides.get(); }
+const Filter *Selector::getFilterReponame() const { return pImpl->filterReponame.get(); }
+
+int
+Selector::set(const DnfPackageSet *pset)
+{
+ if (pImpl->filterName || pImpl->filterProvides || pImpl->filterFile) {
+ return DNF_ERROR_BAD_SELECTOR;
+ }
+ dnf_sack_recompute_considered(pImpl->sack);
+ dnf_sack_make_provides_ready(pImpl->sack);
+ Id id = -1;
+ IdQueue pkgs;
+ while(true) {
+ id = pset->next(id);
+ if (id == -1)
+ break;
+ pkgs.pushBack(id);
+ }
+ pImpl->pkgs = pool_queuetowhatprovides(dnf_sack_get_pool(pImpl->sack), pkgs.getQueue());
+
+ return 0;
+}
+
+int
+Selector::set(int keyname, int cmp_type, const char *match)
+{
+ if (!valid_setting(keyname, cmp_type))
+ return DNF_ERROR_BAD_SELECTOR;
+
+ switch (keyname) {
+ case HY_PKG_ARCH:
+ pImpl->filterArch.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ case HY_PKG_EVR:
+ case HY_PKG_VERSION:
+ pImpl->filterEvr.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ case HY_PKG_NAME:
+ if (pImpl->filterProvides || pImpl->filterFile || pImpl->pkgs)
+ return DNF_ERROR_BAD_SELECTOR;
+ pImpl->filterName.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ case HY_PKG_PROVIDES:
+ if (pImpl->filterName || pImpl->filterFile || pImpl->pkgs)
+ return DNF_ERROR_BAD_SELECTOR;
+ if (cmp_type != HY_GLOB) {
+ try {
+ Dependency reldep(pImpl->sack, match);
+ pImpl->filterProvides.reset(new Filter(keyname, cmp_type, &reldep));
+ return 0;
+ }
+ catch (...) {
+ pImpl->filterProvides.reset();
+ return DNF_ERROR_BAD_SELECTOR;
+ }
+ }
+ pImpl->filterProvides.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ case HY_PKG_REPONAME:
+ pImpl->filterReponame.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ case HY_PKG_FILE:
+ if (pImpl->filterName || pImpl->filterProvides || pImpl->pkgs)
+ return DNF_ERROR_BAD_SELECTOR;
+ pImpl->filterFile.reset(new Filter(keyname, cmp_type, match));
+ return 0;
+ default:
+ return DNF_ERROR_BAD_SELECTOR;
+ }
+}
+
+GPtrArray *
+Selector::matches()
+{
+ DnfSack *sack = pImpl->sack;
+ Pool *pool = dnf_sack_get_pool(sack);
+ Queue job, solvables;
+
+ queue_init(&job);
+ sltrToJob(this, &job, 0);
+
+ queue_init(&solvables);
+ selection_solvables(pool, &job, &solvables);
+
+ GPtrArray *plist = hy_packagelist_create();
+ for (int i = 0; i < solvables.count; i++)
+ g_ptr_array_add(plist, dnf_package_new(sack, solvables.elements[i]));
+
+ queue_free(&solvables);
+ queue_free(&job);
+ return plist;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SELECTOR_HPP
+#define __SELECTOR_HPP
+
+#include <memory>
+
+#include "../hy-selector.h"
+#include "query.hpp"
+
+namespace libdnf {
+
+struct Selector {
+public:
+ Selector(DnfSack* sack);
+ Selector(Selector && src);
+ ~Selector();
+ DnfSack * getSack();
+ const Filter * getFilterArch() const;
+ const Filter * getFilterEvr() const;
+ const Filter * getFilterFile() const;
+ const Filter * getFilterName() const;
+ Id getPkgs() const;
+ const Filter * getFilterProvides() const;
+ const Filter * getFilterReponame() const;
+ int set(const DnfPackageSet * pset);
+ int set(int keyname, int cmp_type, const char *match);
+ GPtrArray * matches();
+private:
+ class Impl;
+ std::unique_ptr<Impl> pImpl;
+};
+
+}
+
+#endif /* __SELECTOR_HPP */
--- /dev/null
+WARNING: libdnf/transaction has no stable API
+
+The code is still under development.
+Consolidation with DNF hasn't fully finished.
+No stable API is guaranteed.
+
+The database schema is considered stable (no major changes expected).
+Avoid using database direcly, tell us your API requirements instead.
--- /dev/null
+set(TRANSACTION_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/Item.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsEnvironmentItem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsGroupItem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/RPMItem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Swdb.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Transaction.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/MergedTransaction.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionItem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionItemReason.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Transformer.cpp
+)
+
+add_subdirectory(private)
+
+set(LIBDNF_SRCS
+ ${LIBDNF_SRCS}
+ ${TRANSACTION_SRCS}
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <algorithm>
+
+#include "CompsEnvironmentItem.hpp"
+
+namespace libdnf {
+
+typedef const char *string;
+
+CompsEnvironmentItem::CompsEnvironmentItem(SQLite3Ptr conn)
+ : Item{conn}
+ , packageTypes{CompsPackageType::DEFAULT}
+{
+}
+
+CompsEnvironmentItem::CompsEnvironmentItem(SQLite3Ptr conn, int64_t pk)
+ : Item{conn}
+ , packageTypes{CompsPackageType::DEFAULT}
+{
+ dbSelect(pk);
+}
+
+void
+CompsEnvironmentItem::save()
+{
+ if (getId() == 0) {
+ dbInsert();
+ } else {
+ // dbUpdate();
+ }
+ for (const auto &i : getGroups()) {
+ i->save();
+ }
+}
+
+void
+CompsEnvironmentItem::dbSelect(int64_t pk)
+{
+ const char *sql = R"**(
+ SELECT
+ environmentid,
+ name,
+ translated_name,
+ pkg_types
+ FROM
+ comps_environment
+ WHERE
+ item_id = ?
+ )**";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(pk);
+ query.step();
+
+ setId(pk);
+ setEnvironmentId(query.get< std::string >("environmentid"));
+ setName(query.get< std::string >("name"));
+ setTranslatedName(query.get< std::string >("translated_name"));
+ setPackageTypes(static_cast< CompsPackageType >(query.get< int >("pkg_types")));
+}
+
+void
+CompsEnvironmentItem::dbInsert()
+{
+ // populates this->id
+ Item::save();
+
+ const char *sql = R"**(
+ INSERT INTO
+ comps_environment (
+ item_id,
+ environmentid,
+ name,
+ translated_name,
+ pkg_types
+ )
+ VALUES
+ (?, ?, ?, ?, ?)
+ )**";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getId(),
+ getEnvironmentId(),
+ getName(),
+ getTranslatedName(),
+ static_cast< int >(getPackageTypes()));
+ query.step();
+}
+
+static TransactionItemPtr
+compsEnvironmentTransactionItemFromQuery(SQLite3Ptr conn, SQLite3::Query &query, int64_t transID)
+{
+ auto trans_item = std::make_shared< TransactionItem >(conn, transID);
+ auto item = std::make_shared< CompsEnvironmentItem >(conn);
+
+ trans_item->setItem(item);
+ trans_item->setId(query.get< int >("ti_id"));
+ trans_item->setAction(static_cast< TransactionItemAction >(query.get< int >("ti_action")));
+ trans_item->setReason(static_cast< TransactionItemReason >(query.get< int >("ti_reason")));
+ trans_item->setState(static_cast< TransactionItemState >(query.get< int >("ti_state")));
+ item->setId(query.get< int >("item_id"));
+ item->setEnvironmentId(query.get< std::string >("environmentid"));
+ item->setName(query.get< std::string >("name"));
+ item->setTranslatedName(query.get< std::string >("translated_name"));
+ item->setPackageTypes(static_cast< CompsPackageType >(query.get< int >("pkg_types")));
+
+ return trans_item;
+}
+
+TransactionItemPtr
+CompsEnvironmentItem::getTransactionItem(SQLite3Ptr conn, const std::string &envid)
+{
+ const char *sql = R"**(
+ SELECT
+ ti.trans_id,
+ ti.id as ti_id,
+ ti.state as ti_state,
+ ti.action as ti_action,
+ ti.reason as ti_reason,
+ i.item_id,
+ i.environmentid,
+ i.name,
+ i.translated_name,
+ i.pkg_types
+ FROM
+ trans_item ti
+ JOIN
+ comps_environment i USING (item_id)
+ JOIN
+ trans t ON ti.trans_id = t.id
+ WHERE
+ t.state = 1
+ /* see comment in TransactionItem.hpp - TransactionItemAction */
+ AND ti.action not in (3, 5, 7)
+ AND i.environmentid = ?
+ ORDER BY
+ ti.trans_id DESC
+ LIMIT 1
+ )**";
+
+ SQLite3::Query query(*conn, sql);
+ query.bindv(envid);
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto trans_item =
+ compsEnvironmentTransactionItemFromQuery(conn, query, query.get< int64_t >("trans_id"));
+
+ if (trans_item->getAction() == TransactionItemAction::REMOVE) {
+ return nullptr;
+ }
+ return trans_item;
+ }
+ return nullptr;
+}
+
+std::vector< TransactionItemPtr >
+CompsEnvironmentItem::getTransactionItemsByPattern(SQLite3Ptr conn, const std::string &pattern)
+{
+ string sql = R"**(
+ SELECT DISTINCT
+ environmentid
+ FROM
+ comps_environment
+ WHERE
+ environmentid LIKE ?
+ OR name LIKE ?
+ OR translated_name LIKE ?
+ )**";
+
+ std::vector< TransactionItemPtr > result;
+
+ // HACK: create a private connection to avoid undefined behavior
+ // after forking process in Anaconda
+ if (conn->getPath() != ":memory:") {
+ conn = std::make_shared<SQLite3>(conn->getPath());
+ }
+ SQLite3::Query query(*conn, sql);
+ std::string pattern_sql = pattern;
+ std::replace(pattern_sql.begin(), pattern_sql.end(), '*', '%');
+ query.bindv(pattern, pattern, pattern);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto groupid = query.get< std::string >("environmentid");
+ auto trans_item = getTransactionItem(conn, groupid);
+ if (!trans_item) {
+ continue;
+ }
+ result.push_back(trans_item);
+ }
+ return result;
+}
+
+std::vector< TransactionItemPtr >
+CompsEnvironmentItem::getTransactionItems(SQLite3Ptr conn, int64_t transactionId)
+{
+ std::vector< TransactionItemPtr > result;
+
+ const char *sql = R"**(
+ SELECT
+ ti.id,
+ ti.state,
+ ti.action,
+ ti.reason,
+ i.item_id,
+ i.environmentid,
+ i.name,
+ i.translated_name,
+ i.pkg_types
+ FROM
+ trans_item ti,
+ comps_environment i
+ WHERE
+ ti.trans_id = ?
+ AND ti.item_id = i.item_id
+ )**";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(transactionId);
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto trans_item = std::make_shared< TransactionItem >(conn, transactionId);
+ auto item = std::make_shared< CompsEnvironmentItem >(conn);
+ trans_item->setItem(item);
+
+ trans_item->setId(query.get< int >(0));
+ trans_item->setState(static_cast< TransactionItemState >(query.get< int >(1)));
+ trans_item->setAction(static_cast< TransactionItemAction >(query.get< int >(2)));
+ trans_item->setReason(static_cast< TransactionItemReason >(query.get< int >(3)));
+ item->setId(query.get< int >(4));
+ item->setEnvironmentId(query.get< std::string >(5));
+ item->setName(query.get< std::string >(6));
+ item->setTranslatedName(query.get< std::string >(7));
+ item->setPackageTypes(static_cast< CompsPackageType >(query.get< int >(8)));
+
+ result.push_back(trans_item);
+ }
+ return result;
+}
+
+std::string
+CompsEnvironmentItem::toStr() const
+{
+ return "@" + getEnvironmentId();
+}
+
+/**
+ * Lazy loader for groups associated with the environment.
+ * \return vector of groups associated with the environment
+ */
+std::vector< CompsEnvironmentGroupPtr >
+CompsEnvironmentItem::getGroups()
+{
+ if (groups.empty()) {
+ loadGroups();
+ }
+ return groups;
+}
+
+void
+CompsEnvironmentItem::loadGroups()
+{
+ const char *sql = R"**(
+ SELECT
+ *
+ FROM
+ comps_environment_group
+ WHERE
+ environment_id = ?
+ ORDER BY
+ groupid ASC
+ )**";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(getId());
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto group = std::make_shared< CompsEnvironmentGroup >(*this);
+ group->setId(query.get< int >("id"));
+ group->setGroupId(query.get< std::string >("groupid"));
+
+ group->setInstalled(query.get< bool >("installed"));
+ group->setGroupType(static_cast< CompsPackageType >(query.get< int >("group_type")));
+ groups.push_back(group);
+ }
+}
+
+CompsEnvironmentGroupPtr
+CompsEnvironmentItem::addGroup(std::string groupId, bool installed, CompsPackageType groupType)
+{
+ // try to find an existing group and override it with the new values
+ CompsEnvironmentGroupPtr grp = nullptr;
+ for (auto & i : groups) {
+ if (i->getGroupId() == groupId) {
+ grp = i;
+ break;
+ }
+ }
+
+ if (grp == nullptr) {
+ grp = std::make_shared< CompsEnvironmentGroup >(*this);
+ groups.push_back(grp);
+ }
+
+ grp->setGroupId(groupId);
+ grp->setInstalled(installed);
+ grp->setGroupType(groupType);
+ return grp;
+}
+
+CompsEnvironmentGroup::CompsEnvironmentGroup(CompsEnvironmentItem &environment)
+ : environment(environment)
+{
+}
+
+void
+CompsEnvironmentGroup::save()
+{
+ if (getId() == 0) {
+ dbInsert();
+ } else {
+ // dbUpdate();
+ }
+}
+
+void
+CompsEnvironmentGroup::dbInsert()
+{
+ const char *sql = R"**(
+ INSERT INTO
+ comps_environment_group (
+ environment_id,
+ groupid,
+ installed,
+ group_type
+ )
+ VALUES
+ (?, ?, ?, ?)
+ )**";
+ SQLite3::Statement query(*getEnvironment().conn, sql);
+ query.bindv(
+ getEnvironment().getId(), getGroupId(), getInstalled(), static_cast< int >(getGroupType()));
+ query.step();
+ setId(getEnvironment().conn->lastInsertRowID());
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_COMPSENVIRONMENTITEM_HPP
+#define LIBDNF_TRANSACTION_COMPSENVIRONMENTITEM_HPP
+
+#include <memory>
+#include <vector>
+
+namespace libdnf {
+
+class CompsEnvironmentItem;
+typedef std::shared_ptr< CompsEnvironmentItem > CompsEnvironmentItemPtr;
+
+class CompsEnvironmentGroup;
+typedef std::shared_ptr< CompsEnvironmentGroup > CompsEnvironmentGroupPtr;
+}
+
+#include "Item.hpp"
+#include "CompsGroupItem.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+class CompsEnvironmentItem : public Item {
+public:
+ explicit CompsEnvironmentItem(SQLite3Ptr conn);
+
+ CompsEnvironmentItem(SQLite3Ptr conn, int64_t pk);
+
+ virtual ~CompsEnvironmentItem() = default;
+
+ const std::string &getEnvironmentId() const noexcept { return environmentId; }
+ void setEnvironmentId(const std::string &value) { environmentId = value; }
+
+ const std::string &getName() const noexcept { return name; }
+ void setName(const std::string &value) { name = value; }
+
+ const std::string &getTranslatedName() const noexcept { return translatedName; }
+ void setTranslatedName(const std::string &value) { translatedName = value; }
+
+ CompsPackageType getPackageTypes() const noexcept { return packageTypes; }
+ void setPackageTypes(CompsPackageType value) { packageTypes = value; }
+
+ std::string toStr() const override;
+ ItemType getItemType() const noexcept override { return itemType; }
+ void save() override;
+ CompsEnvironmentGroupPtr addGroup(std::string groupId,
+ bool installed,
+ CompsPackageType groupType);
+ std::vector< CompsEnvironmentGroupPtr > getGroups();
+ static TransactionItemPtr getTransactionItem(SQLite3Ptr conn, const std::string &envid);
+ static std::vector< TransactionItemPtr > getTransactionItemsByPattern(
+ SQLite3Ptr conn,
+ const std::string &pattern);
+ static std::vector< TransactionItemPtr > getTransactionItems(SQLite3Ptr conn,
+ int64_t transactionId);
+
+protected:
+ const ItemType itemType = ItemType::ENVIRONMENT;
+ std::string environmentId;
+ std::string name;
+ std::string translatedName;
+ CompsPackageType packageTypes = CompsPackageType::DEFAULT;
+
+ void loadGroups();
+ std::vector< CompsEnvironmentGroupPtr > groups;
+
+private:
+ friend class CompsEnvironmentGroup;
+ void dbSelect(int64_t pk);
+ void dbInsert();
+};
+
+class CompsEnvironmentGroup {
+public:
+ explicit CompsEnvironmentGroup(CompsEnvironmentItem &environment);
+
+ int64_t getId() const noexcept { return id; }
+ void setId(int64_t value) { id = value; }
+
+ const CompsEnvironmentItem &getEnvironment() const noexcept { return environment; }
+
+ const std::string &getGroupId() const noexcept { return groupId; }
+ void setGroupId(const std::string &value) { groupId = value; }
+
+ bool getInstalled() const noexcept { return installed; }
+ void setInstalled(bool value) { installed = value; }
+
+ CompsPackageType getGroupType() const noexcept { return groupType; }
+ void setGroupType(CompsPackageType value) { groupType = value; }
+
+ // virtual std::string toStr();
+ void save();
+
+protected:
+ int64_t id = 0;
+ CompsEnvironmentItem &environment;
+ std::string groupId;
+ bool installed = false;
+ CompsPackageType groupType;
+
+private:
+ void dbInsert();
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_COMPSENVIRONMENTITEM_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <algorithm>
+
+#include "CompsGroupItem.hpp"
+#include "TransactionItem.hpp"
+
+#include "libdnf/utils/utils.hpp"
+
+namespace libdnf {
+
+CompsPackageType listToCompsPackageType(const std::vector<std::string> & types)
+{
+ CompsPackageType res{};
+
+ for (const auto & type : types) {
+ if (type == "conditional") {
+ res |= CompsPackageType::CONDITIONAL;
+ } else if (type == "default") {
+ res |= CompsPackageType::DEFAULT;
+ } else if (type == "mandatory") {
+ res |= CompsPackageType::MANDATORY;
+ } else if (type == "optional") {
+ res |= CompsPackageType::OPTIONAL;
+ } else {
+ throw InvalidCompsPackageTypeError("Invalid comps package type \"" +
+ type + "\".");
+ }
+ }
+
+ return res;
+}
+
+CompsPackageType stringToCompsPackageType(const std::string & str)
+{
+ std::vector<std::string> types;
+
+ if (str.empty()) {
+ return CompsPackageType();
+ }
+
+ for (const auto & type : string::split(str, ",")) {
+ types.push_back(string::trim(type));
+ }
+
+ return listToCompsPackageType(types);
+}
+
+std::string compsPackageTypeToString(CompsPackageType type)
+{
+ std::string res;
+ std::string comma = "";
+
+ auto add = [&](const char * str) {
+ res += comma + str;
+
+ if (comma.empty()) {
+ comma = ", ";
+ }
+ };
+
+ if ((type & CompsPackageType::CONDITIONAL) == CompsPackageType::CONDITIONAL) {
+ add("conditional");
+ }
+
+ if ((type & CompsPackageType::DEFAULT) == CompsPackageType::DEFAULT) {
+ add("default");
+ }
+
+ if ((type & CompsPackageType::MANDATORY) == CompsPackageType::MANDATORY) {
+ add("mandatory");
+ }
+
+ if ((type & CompsPackageType::OPTIONAL) == CompsPackageType::OPTIONAL) {
+ add("optional");
+ }
+
+ return res;
+}
+
+CompsGroupItem::CompsGroupItem(SQLite3Ptr conn)
+ : Item{conn}
+ , packageTypes(CompsPackageType::DEFAULT)
+{
+}
+
+CompsGroupItem::CompsGroupItem(SQLite3Ptr conn, int64_t pk)
+ : Item{conn}
+ , packageTypes(CompsPackageType::DEFAULT)
+{
+ dbSelect(pk);
+}
+
+void
+CompsGroupItem::save()
+{
+ if (getId() == 0) {
+ dbInsert();
+ } else {
+ // dbUpdate();
+ }
+ for (auto i : getPackages()) {
+ i->save();
+ }
+}
+
+void
+CompsGroupItem::dbSelect(int64_t pk)
+{
+ const char *sql =
+ "SELECT "
+ " groupid, "
+ " name, "
+ " translated_name, "
+ " pkg_types "
+ "FROM "
+ " comps_group "
+ "WHERE "
+ " item_id = ?";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(pk);
+ query.step();
+
+ setId(pk);
+ setGroupId(query.get< std::string >("groupid"));
+ setName(query.get< std::string >("name"));
+ setTranslatedName(query.get< std::string >("translated_name"));
+ setPackageTypes(static_cast< CompsPackageType >(query.get< int >("pkg_types")));
+}
+
+void
+CompsGroupItem::dbInsert()
+{
+ // populates this->id
+ Item::save();
+
+ const char *sql =
+ "INSERT INTO "
+ " comps_group ( "
+ " item_id, "
+ " groupid, "
+ " name, "
+ " translated_name, "
+ " pkg_types "
+ " ) "
+ "VALUES "
+ " (?, ?, ?, ?, ?)";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getId(),
+ getGroupId(),
+ getName(),
+ getTranslatedName(),
+ static_cast< int >(getPackageTypes()));
+ query.step();
+}
+
+static TransactionItemPtr
+compsGroupTransactionItemFromQuery(SQLite3Ptr conn, SQLite3::Query &query, int64_t transID)
+{
+
+ auto trans_item = std::make_shared< TransactionItem >(conn, transID);
+ auto item = std::make_shared< CompsGroupItem >(conn);
+ trans_item->setItem(item);
+
+ trans_item->setId(query.get< int >("ti_id"));
+ trans_item->setAction(static_cast< TransactionItemAction >(query.get< int >("ti_action")));
+ trans_item->setReason(static_cast< TransactionItemReason >(query.get< int >("ti_reason")));
+ trans_item->setState(static_cast< TransactionItemState >(query.get< int >("ti_state")));
+ item->setId(query.get< int >("item_id"));
+ item->setGroupId(query.get< std::string >("groupid"));
+ item->setName(query.get< std::string >("name"));
+ item->setTranslatedName(query.get< std::string >("translated_name"));
+ item->setPackageTypes(static_cast< CompsPackageType >(query.get< int >("pkg_types")));
+
+ return trans_item;
+}
+
+TransactionItemPtr
+CompsGroupItem::getTransactionItem(SQLite3Ptr conn, const std::string &groupid)
+{
+ const char *sql = R"**(
+ SELECT
+ ti.trans_id,
+ ti.id as ti_id,
+ ti.state as ti_state,
+ ti.action as ti_action,
+ ti.reason as ti_reason,
+ i.item_id,
+ i.groupid,
+ i.name,
+ i.translated_name,
+ i.pkg_types
+ FROM
+ trans_item ti
+ JOIN
+ comps_group i USING (item_id)
+ JOIN
+ trans t ON ti.trans_id = t.id
+ WHERE
+ t.state = 1
+ /* see comment in TransactionItem.hpp - TransactionItemAction */
+ AND ti.action not in (3, 5, 7)
+ AND i.groupid = ?
+ ORDER BY
+ ti.trans_id DESC
+ )**";
+
+ SQLite3::Query query(*conn, sql);
+ query.bindv(groupid);
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto trans_item =
+ compsGroupTransactionItemFromQuery(conn, query, query.get< int64_t >("trans_id"));
+ if (trans_item->getAction() == TransactionItemAction::REMOVE) {
+ return nullptr;
+ }
+ return trans_item;
+ }
+ return nullptr;
+}
+
+std::vector< TransactionItemPtr >
+CompsGroupItem::getTransactionItemsByPattern(SQLite3Ptr conn, const std::string &pattern)
+{
+ const char *sql = R"**(
+ SELECT DISTINCT
+ groupid
+ FROM
+ comps_group
+ WHERE
+ groupid LIKE ?
+ OR name LIKE ?
+ OR translated_name LIKE ?
+ )**";
+
+ std::vector< TransactionItemPtr > result;
+
+ // HACK: create a private connection to avoid undefined behavior
+ // after forking process in Anaconda
+ if (conn->getPath() != ":memory:") {
+ conn = std::make_shared<SQLite3>(conn->getPath());
+ }
+ SQLite3::Query query(*conn, sql);
+ std::string pattern_sql = pattern;
+ std::replace(pattern_sql.begin(), pattern_sql.end(), '*', '%');
+ query.bindv(pattern, pattern, pattern);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto groupid = query.get< std::string >("groupid");
+ auto trans_item = getTransactionItem(conn, groupid);
+ if (!trans_item) {
+ continue;
+ }
+ result.push_back(trans_item);
+ }
+ return result;
+}
+
+std::vector< TransactionItemPtr >
+CompsGroupItem::getTransactionItems(SQLite3Ptr conn, int64_t transactionId)
+{
+ std::vector< TransactionItemPtr > result;
+
+ const char *sql = R"**(
+ SELECT
+ ti.id as ti_id,
+ ti.action as ti_action,
+ ti.reason as ti_reason,
+ ti.state as ti_state,
+ i.item_id,
+ i.groupid,
+ i.name,
+ i.translated_name,
+ i.pkg_types
+ FROM
+ trans_item ti
+ JOIN
+ comps_group i USING (item_id)
+ WHERE
+ ti.trans_id = ?
+ )**";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(transactionId);
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto trans_item = compsGroupTransactionItemFromQuery(conn, query, transactionId);
+ result.push_back(trans_item);
+ }
+ return result;
+}
+
+std::string
+CompsGroupItem::toStr() const
+{
+ return "@" + getGroupId();
+}
+
+/**
+ * Lazy loader for packages associated with the group.
+ * \return list of packages associated with the group (installs and excludes).
+ */
+std::vector< CompsGroupPackagePtr >
+CompsGroupItem::getPackages()
+{
+ if (packages.empty()) {
+ loadPackages();
+ }
+ return packages;
+}
+
+void
+CompsGroupItem::loadPackages()
+{
+ const char *sql =
+ "SELECT "
+ " * "
+ "FROM "
+ " comps_group_package "
+ "WHERE "
+ " group_id = ?";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(getId());
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto pkg = std::make_shared< CompsGroupPackage >(*this);
+ pkg->setId(query.get< int >("id"));
+ pkg->setName(query.get< std::string >("name"));
+ pkg->setInstalled(query.get< bool >("installed"));
+ pkg->setPackageType(static_cast< CompsPackageType >(query.get< int >("pkg_type")));
+ packages.push_back(pkg);
+ }
+}
+
+CompsGroupPackagePtr
+CompsGroupItem::addPackage(std::string name, bool installed, CompsPackageType pkgType)
+{
+ // try to find an existing package and override it with the new values
+ CompsGroupPackagePtr pkg = nullptr;
+ for (auto & i : packages) {
+ if (i->getName() == name) {
+ pkg = i;
+ break;
+ }
+ }
+
+ if (pkg == nullptr) {
+ pkg = std::make_shared< CompsGroupPackage >(*this);
+ packages.push_back(pkg);
+ }
+
+ pkg->setName(name);
+ pkg->setInstalled(installed);
+ pkg->setPackageType(pkgType);
+ return pkg;
+}
+
+CompsGroupPackage::CompsGroupPackage(CompsGroupItem &group)
+ : group(group)
+{
+}
+
+void
+CompsGroupPackage::save()
+{
+ if (getId() == 0) {
+ dbSelectOrInsert();
+ } else {
+ dbUpdate();
+ }
+}
+
+void
+CompsGroupPackage::dbInsert()
+{
+ const char *sql = R"**(
+ INSERT INTO
+ comps_group_package (
+ group_id,
+ name,
+ installed,
+ pkg_type
+ )
+ VALUES
+ (?, ?, ?, ?)
+ )**";
+ SQLite3::Statement query(*getGroup().conn.get(), sql);
+ query.bindv(
+ getGroup().getId(), getName(), getInstalled(), static_cast< int >(getPackageType()));
+ query.step();
+}
+
+void
+CompsGroupPackage::dbUpdate()
+{
+ const char *sql = R"**(
+ UPDATE
+ comps_group_package
+ SET
+ name=?,
+ installed=?,
+ pkg_type=?
+ WHERE
+ id = ?
+ )**";
+ SQLite3::Statement query(*getGroup().conn.get(), sql);
+ query.bindv(
+ getName(), getInstalled(), static_cast< int >(getPackageType()), getId());
+ query.step();
+}
+
+
+void
+CompsGroupPackage::dbSelectOrInsert()
+{
+ const char *sql = R"**(
+ SELECT
+ id
+ FROM
+ comps_group_package
+ WHERE
+ name = ?
+ AND group_id = ?
+ )**";
+
+ SQLite3::Statement query(*getGroup().conn.get(), sql);
+ query.bindv(getName(), getGroup().getId());
+ SQLite3::Statement::StepResult result = query.step();
+
+ if (result == SQLite3::Statement::StepResult::ROW) {
+ setId(query.get< int >(0));
+ dbUpdate();
+ } else {
+ // insert and get the ID back
+ dbInsert();
+ }
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_COMPSGROUPITEM_HPP
+#define LIBDNF_TRANSACTION_COMPSGROUPITEM_HPP
+
+#include "libdnf/error.hpp"
+
+#include <memory>
+#include <vector>
+
+namespace libdnf {
+
+enum class CompsPackageType : int {
+ CONDITIONAL = 1 << 0,
+ DEFAULT = 1 << 1,
+ MANDATORY = 1 << 2,
+ OPTIONAL = 1 << 3
+};
+
+class CompsGroupItem;
+class CompsGroupPackage;
+
+typedef std::shared_ptr< CompsGroupItem > CompsGroupItemPtr;
+typedef std::shared_ptr< CompsGroupPackage > CompsGroupPackagePtr;
+
+CompsPackageType listToCompsPackageType(const std::vector<std::string> & types);
+CompsPackageType stringToCompsPackageType(const std::string & str);
+std::string compsPackageTypeToString(CompsPackageType type);
+
+inline CompsPackageType operator|(CompsPackageType a, CompsPackageType b)
+{
+ return static_cast<CompsPackageType>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline CompsPackageType operator&(CompsPackageType a, CompsPackageType b)
+{
+ return static_cast<CompsPackageType>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+inline CompsPackageType & operator|=(CompsPackageType & a, CompsPackageType b)
+{
+ a = a | b;
+ return a;
+}
+
+inline CompsPackageType & operator&=(CompsPackageType & a, CompsPackageType b)
+{
+ a = a & b;
+ return a;
+}
+
+class InvalidCompsPackageTypeError : public Error {
+public:
+ InvalidCompsPackageTypeError(const std::string & what) : Error(what) {}
+};
+
+}
+
+#include "Item.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+class CompsGroupItem : public Item {
+public:
+ explicit CompsGroupItem(SQLite3Ptr conn);
+ CompsGroupItem(SQLite3Ptr conn, int64_t pk);
+ virtual ~CompsGroupItem() = default;
+
+ const std::string &getGroupId() const noexcept { return groupId; }
+ void setGroupId(const std::string &value) { groupId = value; }
+
+ const std::string &getName() const noexcept { return name; }
+ void setName(const std::string &value) { name = value; }
+
+ const std::string &getTranslatedName() const noexcept { return translatedName; }
+ void setTranslatedName(const std::string &value) { translatedName = value; }
+
+ CompsPackageType getPackageTypes() const noexcept { return packageTypes; }
+ void setPackageTypes(CompsPackageType value) { packageTypes = value; }
+
+ std::string toStr() const override;
+ ItemType getItemType() const noexcept override { return itemType; }
+ void save() override;
+ CompsGroupPackagePtr addPackage(std::string name, bool installed, CompsPackageType pkgType);
+ std::vector< CompsGroupPackagePtr > getPackages();
+ static TransactionItemPtr getTransactionItem(SQLite3Ptr conn, const std::string &groupid);
+ static std::vector< TransactionItemPtr > getTransactionItemsByPattern(
+ SQLite3Ptr conn,
+ const std::string &pattern);
+ static std::vector< TransactionItemPtr > getTransactionItems(SQLite3Ptr conn,
+ int64_t transactionId);
+
+protected:
+ const ItemType itemType = ItemType::GROUP;
+ std::string groupId;
+ std::string name;
+ std::string translatedName;
+ CompsPackageType packageTypes;
+
+ void loadPackages();
+ std::vector< CompsGroupPackagePtr > packages;
+
+private:
+ friend class CompsGroupPackage;
+ void dbSelect(int64_t pk);
+ void dbInsert();
+};
+
+class CompsGroupPackage {
+public:
+ explicit CompsGroupPackage(CompsGroupItem &group);
+
+ int64_t getId() const noexcept { return id; }
+ void setId(int64_t value) { id = value; }
+
+ const CompsGroupItem &getGroup() const noexcept { return group; }
+
+ const std::string &getName() const noexcept { return name; }
+ void setName(const std::string &value) { name = value; }
+
+ bool getInstalled() const noexcept { return installed; }
+ void setInstalled(bool value) { installed = value; }
+
+ CompsPackageType getPackageType() const noexcept { return packageType; }
+ void setPackageType(CompsPackageType value) { packageType = value; }
+
+ // virtual std::string toStr();
+ void save();
+
+protected:
+ int64_t id = 0;
+ CompsGroupItem &group;
+ std::string name;
+ bool installed = false;
+ CompsPackageType packageType = CompsPackageType::DEFAULT;
+
+private:
+ void dbInsert();
+ void dbSelectOrInsert();
+ void dbUpdate();
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_COMPSGROUPITEM_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Item.hpp"
+
+namespace libdnf {
+
+Item::Item(SQLite3Ptr conn)
+ : conn{conn}
+{
+}
+
+void
+Item::save()
+{
+ dbInsert();
+}
+
+void
+Item::dbInsert()
+{
+ const char *sql =
+ "INSERT INTO "
+ " item "
+ "VALUES "
+ " (null, ?)";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(static_cast< int >(itemType));
+ query.step();
+ setId(conn->lastInsertRowID());
+}
+
+std::string
+Item::toStr() const
+{
+ return "<Item #" + std::to_string(getId()) + ">";
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_ITEM_HPP
+#define LIBDNF_TRANSACTION_ITEM_HPP
+
+#include <memory>
+#include <string>
+
+#include "../utils/sqlite3/Sqlite3.hpp"
+
+namespace libdnf {
+class Item;
+typedef std::shared_ptr< Item > ItemPtr;
+}
+
+#include "Types.hpp"
+
+namespace libdnf {
+
+class Item {
+public:
+ /// Default constructor.
+ explicit Item(SQLite3Ptr conn);
+
+ /// Default destructor.
+ virtual ~Item() = default;
+
+ /// Returns the ID of this item.
+ int64_t getId() const noexcept { return id; }
+
+ /// Sets the ID of this item.
+ void setId(int64_t value) { id = value; }
+
+ virtual ItemType getItemType() const noexcept { return itemType; }
+ virtual std::string toStr() const;
+ virtual void save();
+
+protected:
+ void dbInsert();
+
+ SQLite3Ptr conn;
+ int64_t id = 0;
+ const ItemType itemType = ItemType::UNKNOWN;
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_ITEM_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "MergedTransaction.hpp"
+#include <algorithm>
+#include <vector>
+
+namespace libdnf {
+
+/**
+ * Create a new MergedTransaction object with a single transaction
+ * \param trans initial transaction
+ */
+MergedTransaction::MergedTransaction(TransactionPtr trans)
+ : transactions{trans}
+{
+}
+
+/**
+ * Merge \trans into this transaction
+ * Internally, transactions are kept in a sorted vector, what allows to
+ * easily access merged transaction properties on demand.
+ * \param trans transaction to be merged with
+ */
+void
+MergedTransaction::merge(TransactionPtr trans)
+{
+ bool inserted = false;
+ for (auto it = transactions.begin(); it < transactions.end(); ++it) {
+ if ((*it)->getId() > trans->getId()) {
+ transactions.insert(it, trans);
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted) {
+ transactions.push_back(trans);
+ }
+}
+
+/**
+ * Get IDs of the transactions involved in the merged transaction
+ * \return list of transaction IDs sorted in ascending order
+ */
+std::vector< int64_t >
+MergedTransaction::listIds() const
+{
+ std::vector< int64_t > ids;
+ for (auto t : transactions) {
+ ids.push_back(t->getId());
+ }
+ return ids;
+}
+
+/**
+ * Get UNIX IDs of users who performed the transaction.
+ * \return list of user IDs sorted by transaction ID in ascending order
+ */
+std::vector< uint32_t >
+MergedTransaction::listUserIds() const
+{
+ std::vector< uint32_t > users;
+ for (auto t : transactions) {
+ users.push_back(t->getUserId());
+ }
+ return users;
+}
+
+/**
+ * Get list of commands that started the transaction
+ * \return list of commands sorted by transaction ID in ascending order
+ */
+std::vector< std::string >
+MergedTransaction::listCmdlines() const
+{
+ std::vector< std::string > cmdLines;
+ for (auto t : transactions) {
+ cmdLines.push_back(t->getCmdline());
+ }
+ return cmdLines;
+}
+
+std::vector< TransactionState >
+MergedTransaction::listStates() const
+{
+ std::vector< TransactionState > result;
+ for (auto t : transactions) {
+ result.push_back(t->getState());
+ }
+ return result;
+}
+
+std::vector< std::string >
+MergedTransaction::listReleasevers() const
+{
+ std::vector< std::string > result;
+ for (auto t : transactions) {
+ result.push_back(t->getReleasever());
+ }
+ return result;
+}
+
+std::vector< std::string >
+MergedTransaction::listComments() const
+{
+ std::vector< std::string > result;
+ for (auto t : transactions) {
+ result.push_back(t->getComment());
+ }
+ return result;
+}
+
+
+int64_t
+MergedTransaction::getDtBegin() const noexcept
+{
+ return transactions.front()->getDtBegin();
+}
+int64_t
+MergedTransaction::getDtEnd() const noexcept
+{
+ return transactions.back()->getDtEnd();
+}
+const std::string &
+MergedTransaction::getRpmdbVersionBegin() const noexcept
+{
+ return transactions.front()->getRpmdbVersionBegin();
+}
+
+const std::string &
+MergedTransaction::getRpmdbVersionEnd() const noexcept
+{
+ return transactions.back()->getRpmdbVersionEnd();
+}
+
+std::set< RPMItemPtr >
+MergedTransaction::getSoftwarePerformedWith() const
+{
+ std::set< RPMItemPtr > software;
+ for (auto t : transactions) {
+ auto tranSoft = t->getSoftwarePerformedWith();
+ software.insert(tranSoft.begin(), tranSoft.end());
+ }
+ return software;
+}
+
+std::vector< std::pair< int, std::string > >
+MergedTransaction::getConsoleOutput()
+{
+ std::vector< std::pair< int, std::string > > output;
+ for (auto t : transactions) {
+ auto tranOutput = t->getConsoleOutput();
+ output.insert(output.end(), tranOutput.begin(), tranOutput.end());
+ }
+ return output;
+}
+
+
+static bool transaction_item_sort_function(const std::shared_ptr<TransactionItemBase> lhs, const std::shared_ptr<TransactionItemBase> rhs) {
+ if (lhs->isForwardAction() && rhs->isForwardAction()) {
+ return false;
+ }
+ if (lhs->isBackwardAction() && rhs->isBackwardAction()) {
+ return false;
+ }
+ if (lhs->isBackwardAction()) {
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Get list of transaction items involved in the merged transaction
+ * Actions are merged using following rules:
+ * (old action) -> (new action) = (merged action)
+ *
+ * Erase/Obsolete -> Install/Obsoleting = Downgrade/Upgrade
+ *
+ * Reinstall/Reason change -> (new action) = (new action)
+ *
+ * Install -> Erase = (nothing)
+ *
+ * Install -> Upgrade/Downgrade = Install (with Upgrade version)
+ *
+ * Downgrade/Upgrade/Obsoleting -> Reinstall = (old action)
+ *
+ * Downgrade/Upgrade/Obsoleting -> Erase/Obsoleted = Erase/Obsolete (with old package)
+ *
+ * Downgrade/Upgrade/Obsoleting -> Downgraded/Upgrade =
+ * We have differentiate between original transaction, and new one.
+ * When a transaction package pair is not complete, then we are still in original one.
+ *
+ * With complete transaction pair we need to get a new Upgrade/Downgrade package and
+ * compare versions with original package from pair.
+ *
+ * Additionally, if a package is installed both before and after the list of transactions
+ * with the same version, no action will be taken.
+ */
+std::vector< TransactionItemBasePtr >
+MergedTransaction::getItems()
+{
+ ItemPairMap itemPairMap;
+
+ // iterate over transaction
+ for (auto t : transactions) {
+ auto transItems = t->getItems();
+ // sort transaction items by their action type - forward/backward
+ // this fixes behavior of the merging algorithm in several edge cases
+ std::sort(transItems.begin(), transItems.end(), transaction_item_sort_function);
+ // iterate over transaction items
+ for (auto transItem : transItems) {
+ // get item and its type
+ auto mTransItem = std::dynamic_pointer_cast< TransactionItemBase >(transItem);
+ mergeItem(itemPairMap, mTransItem);
+ }
+ }
+
+ std::vector< TransactionItemBasePtr > items;
+ for (const auto &row : itemPairMap) {
+ ItemPair itemPair = row.second;
+ items.push_back(itemPair.first);
+ if (itemPair.second != nullptr) {
+ items.push_back(itemPair.second);
+ }
+ }
+ return items;
+}
+
+static std::string
+getItemIdentifier(ItemPtr item)
+{
+ auto itemType = item->getItemType();
+ std::string name;
+ if (itemType == ItemType::RPM) {
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(item);
+ name = rpm->getName() + "." + rpm->getArch();
+ } else if (itemType == ItemType::GROUP) {
+ auto group = std::dynamic_pointer_cast< CompsGroupItem >(item);
+ name = group->getGroupId();
+ } else if (itemType == ItemType::ENVIRONMENT) {
+ auto env = std::dynamic_pointer_cast< CompsEnvironmentItem >(item);
+ name = env->getEnvironmentId();
+ }
+ return name;
+}
+
+/**
+ * Resolve the difference between RPMs in the first and second transaction item
+ * and create a ItemPair of Upgrade, Downgrade or remove the item from the merged
+ * transaction set in case of both packages are the same.
+ * Method is called when original package is being removed and then installed again.
+ * \param itemPairMap merged transaction set
+ * \param previousItemPair original item pair
+ * \param mTransItem new transaction item
+ * \return true if the original and new transaction item differ
+ */
+bool
+MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
+ TransactionItemBasePtr mTransItem)
+{
+ auto firstItem = previousItemPair.first->getItem();
+ auto secondItem = mTransItem->getItem();
+
+ auto firstRPM = std::dynamic_pointer_cast< RPMItem >(firstItem);
+ auto secondRPM = std::dynamic_pointer_cast< RPMItem >(secondItem);
+
+ if (firstRPM->getVersion() == secondRPM->getVersion() &&
+ firstRPM->getEpoch() == secondRPM->getEpoch() &&
+ firstRPM->getRelease() == secondRPM->getRelease()) {
+ // Drop the item from merged transaction
+ itemPairMap.erase(getItemIdentifier(firstItem));
+ return false;
+ } else if ((*firstRPM) < (*secondRPM)) {
+ // Upgrade to secondRPM
+ previousItemPair.first->setAction(TransactionItemAction::UPGRADED);
+ mTransItem->setAction(TransactionItemAction::UPGRADE);
+ } else {
+ // Downgrade to secondRPM
+ previousItemPair.first->setAction(TransactionItemAction::DOWNGRADED);
+ mTransItem->setAction(TransactionItemAction::DOWNGRADE);
+ }
+ previousItemPair.second = mTransItem;
+ return true;
+}
+
+void
+MergedTransaction::resolveErase(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
+ TransactionItemBasePtr mTransItem)
+{
+ /*
+ * The original item has been removed - it has to be installed now unless the rpmdb
+ * has changed. Resolve the difference between packages and mark it as Upgrade,
+ * Downgrade or remove it from the transaction
+ */
+ if (mTransItem->getAction() == TransactionItemAction::INSTALL) {
+ if (mTransItem->getItem()->getItemType() == ItemType::RPM) {
+ // resolve the difference between RPM packages
+ if (!resolveRPMDifference(itemPairMap, previousItemPair, mTransItem)) {
+ return;
+ }
+ } else {
+ // difference between comps can't be resolved
+ mTransItem->setAction(TransactionItemAction::REINSTALL);
+ }
+ }
+ previousItemPair.first = mTransItem;
+ previousItemPair.second = nullptr;
+}
+
+/**
+ * Resolve altered - Upgrade(d)/Downgrade(d) transaction items.
+ * If the new item is Erased or Obsoleted, than its action is transferred to the original pair.
+ * When its being Downgraded/Upgraded and the pair is incomplete then we are in the same
+ * transaction - new package is used to complete the pair. Items are stored in pairs (Upgrade,
+ * Upgrade) or (Downgraded, Downgrade). With complete transaction pair we need to get the new
+ * Upgrade/Downgrade item and compare its version with the original item from the pair.
+ * \param itemPairMap merged transaction set
+ * \param previousItemPair original item pair
+ * \param mTransItem new transaction item
+ */
+void
+MergedTransaction::resolveAltered(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
+ TransactionItemBasePtr mTransItem)
+{
+ auto newState = mTransItem->getAction();
+ auto firstState = previousItemPair.first->getAction();
+
+ if (newState == TransactionItemAction::REMOVE || newState == TransactionItemAction::OBSOLETED) {
+ // package is being Erased
+ // move Erased action to the previous state
+ previousItemPair.first->setAction(newState);
+ previousItemPair.second = nullptr;
+ } else if (newState == TransactionItemAction::DOWNGRADED ||
+ newState == TransactionItemAction::UPGRADED) {
+ // check if the transaction pair is complete
+ if (previousItemPair.second == nullptr) {
+ // pair might be in a wrong order
+ if (firstState == TransactionItemAction::DOWNGRADE ||
+ firstState == TransactionItemAction::UPGRADE) {
+ // fix the order
+ previousItemPair.second = previousItemPair.first;
+ previousItemPair.first = mTransItem;
+ }
+ }
+ // XXX handle obsoleting state -> state is not supported anymore, so it can't
+ // occur anymore - maybe we should set some "Obsoleting" flag or what
+ // state of obsoleting package should be transferred to a new package
+ /*
+ * Otherwise we can just drop the package
+ * Original package from new transaction should be the same as a new package
+ * from previous transaction - unless the RPMDB has altered.
+ */
+
+ } else if (newState == TransactionItemAction::DOWNGRADE ||
+ newState == TransactionItemAction::UPGRADE) {
+ /*
+ * Check whether second item is missing in transaction pair
+ * When it does, complete the transaction pair.
+ */
+ if (previousItemPair.second == nullptr) {
+ previousItemPair.second = mTransItem;
+ } else {
+ if (mTransItem->getItem()->getItemType() == ItemType::RPM) {
+ // resolve the difference between RPM packages
+ resolveRPMDifference(itemPairMap, previousItemPair, mTransItem);
+ } else {
+ // difference between comps can't be resolved
+ previousItemPair.second->setAction(TransactionItemAction::REINSTALL);
+ previousItemPair.first = previousItemPair.second;
+ previousItemPair.second = nullptr;
+ }
+ }
+ }
+}
+
+/**
+ * Merge transaction item into merged transaction set
+ * \param itemPairMap merged transaction set
+ * \param mTransItem transaction item
+ */
+void
+MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mTransItem)
+{
+ // get item identifier
+ std::string name = getItemIdentifier(mTransItem->getItem());
+
+ auto previous = itemPairMap.find(name);
+ if (previous == itemPairMap.end()) {
+ itemPairMap[name] = ItemPair(mTransItem, nullptr);
+ return;
+ }
+
+ ItemPair &previousItemPair = previous->second;
+
+ auto firstState = previousItemPair.first->getAction();
+ auto newState = mTransItem->getAction();
+
+ switch (firstState) {
+ case TransactionItemAction::REMOVE:
+ case TransactionItemAction::OBSOLETED:
+ resolveErase(itemPairMap, previousItemPair, mTransItem);
+ break;
+ case TransactionItemAction::INSTALL:
+ // the original package has been installed -> it may be either Removed, or altered
+ if (newState == TransactionItemAction::REMOVE ||
+ newState == TransactionItemAction::OBSOLETED) {
+ // Install -> Remove = (nothing)
+ itemPairMap.erase(name);
+ break;
+ } else if (mTransItem->isBackwardAction()) {
+ break;
+ }
+ // altered -> transfer install to the altered package
+ mTransItem->setAction(TransactionItemAction::INSTALL);
+ // don't break
+ case TransactionItemAction::REINSTALL:
+ case TransactionItemAction::REASON_CHANGE:
+ // The original item has been reinstalled or the reason has been changed
+ // keep the new action
+ previousItemPair.first = mTransItem;
+ previousItemPair.second = nullptr;
+ break;
+ case TransactionItemAction::DOWNGRADE:
+ case TransactionItemAction::DOWNGRADED:
+ case TransactionItemAction::UPGRADE:
+ case TransactionItemAction::UPGRADED:
+ case TransactionItemAction::OBSOLETE:
+ resolveAltered(itemPairMap, previousItemPair, mTransItem);
+ break;
+ case TransactionItemAction::REINSTALLED:
+ break;
+ }
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_MERGEDTRANSACTION_HPP
+#define LIBDNF_TRANSACTION_MERGEDTRANSACTION_HPP
+
+#include <memory>
+#include <set>
+#include <string>
+#include <map>
+#include <vector>
+
+namespace libdnf {
+
+class MergedTransaction;
+typedef std::shared_ptr< MergedTransaction > MergedTransactionPtr;
+}
+
+#include "RPMItem.hpp"
+#include "Transaction.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+class MergedTransaction {
+public:
+ explicit MergedTransaction(TransactionPtr trans);
+ void merge(TransactionPtr trans);
+
+ std::vector< int64_t > listIds() const;
+ std::vector< uint32_t > listUserIds() const;
+ std::vector< std::string > listCmdlines() const;
+ std::vector< TransactionState > listStates() const;
+ std::vector< std::string > listReleasevers() const;
+ std::vector< std::string > listComments() const;
+ int64_t getDtBegin() const noexcept;
+ int64_t getDtEnd() const noexcept;
+ const std::string &getRpmdbVersionBegin() const noexcept;
+ const std::string &getRpmdbVersionEnd() const noexcept;
+ std::set< RPMItemPtr > getSoftwarePerformedWith() const;
+ std::vector< std::pair< int, std::string > > getConsoleOutput();
+
+ std::vector< TransactionItemBasePtr > getItems();
+
+protected:
+ std::vector< TransactionPtr > transactions;
+
+ struct ItemPair {
+ ItemPair(TransactionItemBasePtr first, TransactionItemBasePtr second)
+ : first{first}
+ , second{second}
+ {
+ }
+ ItemPair(){};
+ TransactionItemBasePtr first = nullptr;
+ TransactionItemBasePtr second = nullptr;
+ };
+
+ typedef std::map< std::string, ItemPair > ItemPairMap;
+
+ void mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr transItem);
+ bool resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ void resolveErase(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ void resolveAltered(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_TRANSACTION_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <algorithm>
+#include <map>
+#include <sstream>
+
+#include "../hy-subject.h"
+#include "../nevra.hpp"
+
+#include "RPMItem.hpp"
+
+namespace libdnf {
+
+RPMItem::RPMItem(SQLite3Ptr conn)
+ : Item{conn}
+{
+}
+
+RPMItem::RPMItem(SQLite3Ptr conn, int64_t pk)
+ : Item{conn}
+{
+ dbSelect(pk);
+}
+
+void
+RPMItem::save()
+{
+ if (getId() == 0) {
+ dbSelectOrInsert();
+ } else {
+ // TODO: dbUpdate() ?
+ }
+}
+
+void
+RPMItem::dbSelect(int64_t pk)
+{
+ const char *sql =
+ "SELECT "
+ " name, "
+ " epoch, "
+ " version, "
+ " release, "
+ " arch "
+ "FROM "
+ " rpm "
+ "WHERE "
+ " item_id = ?";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(pk);
+ query.step();
+
+ setId(pk);
+ setName(query.get< std::string >(0));
+ setEpoch(query.get< int >(1));
+ setVersion(query.get< std::string >(2));
+ setRelease(query.get< std::string >(3));
+ setArch(query.get< std::string >(4));
+}
+
+void
+RPMItem::dbInsert()
+{
+ // populates this->id
+ Item::save();
+
+ const char *sql =
+ "INSERT INTO "
+ " rpm "
+ "VALUES "
+ " (?, ?, ?, ?, ?, ?)";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getId(), getName(), getEpoch(), getVersion(), getRelease(), getArch());
+ query.step();
+}
+
+static TransactionItemPtr
+transactionItemFromQuery(SQLite3Ptr conn, SQLite3::Query &query, int64_t transID)
+{
+ auto trans_item = std::make_shared< TransactionItem >(conn, transID);
+ auto item = std::make_shared< RPMItem >(conn);
+ trans_item->setItem(item);
+ trans_item->setId(query.get< int >("id"));
+ trans_item->setAction(static_cast< TransactionItemAction >(query.get< int >("action")));
+ trans_item->setReason(static_cast< TransactionItemReason >(query.get< int >("reason")));
+ trans_item->setRepoid(query.get< std::string >("repoid"));
+ trans_item->setState(static_cast< TransactionItemState >(query.get< int >("state")));
+ item->setId(query.get< int >("item_id"));
+ item->setName(query.get< std::string >("name"));
+ item->setEpoch(query.get< int >("epoch"));
+ item->setVersion(query.get< std::string >("version"));
+ item->setRelease(query.get< std::string >("release"));
+ item->setArch(query.get< std::string >("arch"));
+ return trans_item;
+}
+
+std::vector< TransactionItemPtr >
+RPMItem::getTransactionItems(SQLite3Ptr conn, int64_t transaction_id)
+{
+ std::vector< TransactionItemPtr > result;
+
+ const char *sql =
+ "SELECT "
+ // trans_item
+ " ti.id, "
+ " ti.action, "
+ " ti.reason, "
+ " ti.state, "
+ // repo
+ " r.repoid, "
+ // rpm
+ " i.item_id, "
+ " i.name, "
+ " i.epoch, "
+ " i.version, "
+ " i.release, "
+ " i.arch "
+ "FROM "
+ " trans_item ti, "
+ " repo r, "
+ " rpm i "
+ "WHERE "
+ " ti.trans_id = ? "
+ " AND ti.repo_id = r.id "
+ " AND ti.item_id = i.item_id";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(transaction_id);
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ result.push_back(transactionItemFromQuery(conn, query, transaction_id));
+ }
+ return result;
+}
+
+std::string
+RPMItem::getNEVRA() const
+{
+ // TODO: use string formatting
+ if (epoch > 0) {
+ return name + "-" + std::to_string(epoch) + ":" + version + "-" + release + "." + arch;
+ }
+ return name + "-" + version + "-" + release + "." + arch;
+}
+
+std::string
+RPMItem::toStr() const
+{
+ return getNEVRA();
+}
+
+void
+RPMItem::dbSelectOrInsert()
+{
+ const char *sql =
+ "SELECT "
+ " item_id "
+ "FROM "
+ " rpm "
+ "WHERE "
+ " name = ? "
+ " AND epoch = ? "
+ " AND version = ? "
+ " AND release = ? "
+ " AND arch = ?";
+
+ SQLite3::Statement query(*conn.get(), sql);
+
+ query.bindv(getName(), getEpoch(), getVersion(), getRelease(), getArch());
+ SQLite3::Statement::StepResult result = query.step();
+
+ if (result == SQLite3::Statement::StepResult::ROW) {
+ setId(query.get< int >(0));
+ } else {
+ // insert and get the ID back
+ dbInsert();
+ }
+}
+
+TransactionItemPtr
+RPMItem::getTransactionItem(SQLite3Ptr conn, const std::string &nevra)
+{
+ Nevra nevraObject;
+ if (!nevraObject.parse(nevra.c_str(), HY_FORM_NEVRA)) {
+ return nullptr;
+ }
+ // TODO: hy_nevra_possibility should set epoch to 0 if epoch is not specified and HY_FORM_NEVRA
+ // is used
+ if (nevraObject.getEpoch() < 0) {
+ nevraObject.setEpoch(0);
+ }
+
+ const char *sql = R"**(
+ SELECT
+ ti.trans_id,
+ ti.id,
+ ti.action,
+ ti.reason,
+ ti.state,
+ r.repoid,
+ i.item_id,
+ i.name,
+ i.epoch,
+ i.version,
+ i.release,
+ i.arch
+ FROM
+ trans_item ti,
+ repo r,
+ rpm i
+ WHERE
+ ti.repo_id = r.id
+ AND ti.item_id = i.item_id
+ AND i.name = ?
+ AND i.epoch = ?
+ AND i.version = ?
+ AND i.release = ?
+ AND i.arch = ?
+ ORDER BY
+ ti.id DESC
+ LIMIT 1
+ )**";
+ SQLite3::Query query(*conn, sql);
+ query.bindv(nevraObject.getName(),
+ nevraObject.getEpoch(),
+ nevraObject.getVersion(),
+ nevraObject.getRelease(),
+ nevraObject.getArch());
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ return transactionItemFromQuery(conn, query, query.get< int64_t >("trans_id"));
+ }
+ return nullptr;
+}
+
+TransactionItemReason
+RPMItem::resolveTransactionItemReason(SQLite3Ptr conn,
+ const std::string &name,
+ const std::string &arch,
+ int64_t maxTransactionId)
+{
+ // NOTE: All negative maxTransactionId values are treated the same. The
+ // method is called with maxTransactionId = -2 in a couple of places, the
+ // semantics here have been the same as with -1 for a long time. If it
+ // ain't broke...
+ std::string sql = R"**(
+ SELECT
+ ti.action as action,
+ ti.reason as reason
+ FROM
+ trans_item ti
+ JOIN
+ trans t ON ti.trans_id = t.id
+ JOIN
+ rpm i USING (item_id)
+ WHERE
+ t.state = 1
+ /* see comment in TransactionItem.hpp - TransactionItemAction */
+ AND ti.action not in (3, 5, 7, 10)
+ AND i.name = ?
+ AND i.arch = ?
+ )**";
+
+ if (maxTransactionId >= 0) {
+ sql.append(" AND ti.trans_id <= ?");
+ }
+
+ sql.append(R"**(
+ ORDER BY
+ ti.trans_id DESC
+ LIMIT 1
+ )**");
+
+ if (arch != "") {
+ SQLite3::Query query(*conn, sql);
+ if (maxTransactionId >= 0) {
+ query.bindv(name, arch, maxTransactionId);
+ } else {
+ query.bindv(name, arch);
+ }
+
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto action = static_cast< TransactionItemAction >(query.get< int64_t >("action"));
+ if (action == TransactionItemAction::REMOVE) {
+ return TransactionItemReason::UNKNOWN;
+ }
+ auto reason = static_cast< TransactionItemReason >(query.get< int64_t >("reason"));
+ return reason;
+ }
+ } else {
+ const char *arch_sql = R"**(
+ SELECT DISTINCT
+ arch
+ FROM
+ rpm
+ WHERE
+ name = ?
+ )**";
+
+ SQLite3::Query arch_query(*conn, arch_sql);
+ arch_query.bindv(name);
+
+ TransactionItemReason result = TransactionItemReason::UNKNOWN;
+
+ while (arch_query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto rpm_arch = arch_query.get< std::string >("arch");
+
+ SQLite3::Query query(*conn, sql);
+ query.bindv(name, rpm_arch);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto action = static_cast< TransactionItemAction >(query.get< int64_t >("action"));
+ if (action == TransactionItemAction::REMOVE) {
+ continue;
+ }
+ auto reason = static_cast< TransactionItemReason >(query.get< int64_t >("reason"));
+ if (reason > result) {
+ result = reason;
+ }
+ }
+ }
+ return result;
+ }
+ return TransactionItemReason::UNKNOWN;
+}
+
+/**
+ * Compare RPM packages
+ * This method doesn't care about compare package names
+ * \param other RPMItem to compare with
+ * \return true if other package is newer (has higher version and/or epoch)
+ */
+bool
+RPMItem::operator<(const RPMItem &other) const
+{
+ // compare epochs
+ int32_t epochDif = other.getEpoch() - getEpoch();
+ if (epochDif > 0) {
+ return true;
+ } else if (epoch < 0) {
+ return false;
+ }
+
+ // compare versions
+ std::stringstream versionThis(getVersion());
+ std::stringstream versionOther(other.getVersion());
+
+ std::string bufferThis;
+ std::string bufferOther;
+ while (std::getline(versionThis, bufferThis, '.') &&
+ std::getline(versionOther, bufferOther, '.')) {
+ int subVersionThis = std::stoi(bufferThis);
+ int subVersionOther = std::stoi(bufferOther);
+ if (subVersionThis == subVersionOther) {
+ continue;
+ }
+ return subVersionOther > subVersionThis;
+ }
+ return false;
+}
+
+std::vector< int64_t >
+RPMItem::searchTransactions(SQLite3Ptr conn, const std::vector< std::string > &patterns)
+{
+ std::vector< int64_t > result;
+
+ const char *sql = R"**(
+ SELECT DISTINCT
+ t.id
+ FROM
+ trans t
+ JOIN
+ trans_item ti ON ti.trans_id = t.id
+ JOIN
+ rpm i USING (item_id)
+ WHERE
+ t.state = 1
+ AND (
+ i.name = ?
+ OR i.epoch = ?
+ OR i.version = ?
+ OR i.release = ?
+ OR i.arch = ?
+ )
+ ORDER BY
+ trans_id DESC
+ )**";
+ SQLite3::Query query(*conn, sql);
+ for (auto pattern : patterns) {
+ query.bindv(pattern, pattern, pattern, pattern, pattern);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ result.push_back(query.get< int64_t >("id"));
+ }
+ }
+ std::sort(result.begin(), result.end());
+ auto last = std::unique(result.begin(), result.end());
+ result.erase(last, result.end());
+ return result;
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_RPMITEM_HPP
+#define LIBDNF_TRANSACTION_RPMITEM_HPP
+
+#include <memory>
+#include <vector>
+
+namespace libdnf {
+class RPMItem;
+typedef std::shared_ptr< RPMItem > RPMItemPtr;
+}
+
+#include "Item.hpp"
+#include "TransactionItem.hpp"
+#include "Types.hpp"
+
+namespace libdnf {
+
+class RPMItem : public Item {
+public:
+ explicit RPMItem(SQLite3Ptr conn);
+ RPMItem(SQLite3Ptr conn, int64_t pk);
+ virtual ~RPMItem() = default;
+
+ const std::string &getName() const noexcept { return name; }
+ void setName(const std::string &value) { name = value; }
+
+ int32_t getEpoch() const noexcept { return epoch; }
+ void setEpoch(int32_t value) { epoch = value; }
+
+ const std::string &getVersion() const noexcept { return version; }
+ void setVersion(const std::string &value) { version = value; }
+
+ const std::string &getRelease() const noexcept { return release; }
+ void setRelease(const std::string &value) { release = value; }
+
+ const std::string &getArch() const noexcept { return arch; }
+ void setArch(const std::string &value) { arch = value; }
+
+ std::string getNEVRA() const;
+ std::string toStr() const override;
+ ItemType getItemType() const noexcept override { return itemType; }
+ void save() override;
+
+ static TransactionItemPtr getTransactionItem(SQLite3Ptr conn, const std::string &nevra);
+ static std::vector< int64_t > searchTransactions(SQLite3Ptr conn, const std::vector< std::string > &patterns);
+ static std::vector< TransactionItemPtr > getTransactionItems(SQLite3Ptr conn,
+ int64_t transaction_id);
+ static TransactionItemReason resolveTransactionItemReason(SQLite3Ptr conn,
+ const std::string &name,
+ const std::string &arch,
+ int64_t maxTransactionId);
+
+ bool operator<(const RPMItem &other) const;
+
+protected:
+ const ItemType itemType = ItemType::RPM;
+ std::string name;
+ int32_t epoch = 0;
+ std::string version;
+ std::string release;
+ std::string arch;
+
+ void dbSelect(int64_t transaction_id);
+ void dbInsert();
+ void dbSelectOrInsert();
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_RPMITEM_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cstdio>
+#include <solv/bitmap.h>
+#include <solv/solvable.h>
+
+#include "../hy-query-private.hpp"
+#include "../hy-subject.h"
+#include "../nevra.hpp"
+
+#include "../sack/packageset.hpp"
+
+#include "../log.hpp"
+#include "../utils/bgettext/bgettext-lib.h"
+#include "../utils/filesystem.hpp"
+#include "../utils/sqlite3/Sqlite3.hpp"
+#include "../utils/tinyformat/tinyformat.hpp"
+
+#include "RPMItem.hpp"
+#include "Swdb.hpp"
+#include "Transformer.hpp"
+
+namespace libdnf {
+
+Swdb::Swdb(SQLite3Ptr conn)
+ : conn{conn}
+ , autoClose(true)
+{
+ Transformer::migrateSchema(conn);
+}
+
+Swdb::Swdb(SQLite3Ptr conn, bool autoClose)
+ : conn{conn}
+ , autoClose(autoClose)
+{
+ Transformer::migrateSchema(conn);
+}
+
+Swdb::Swdb(const std::string &path)
+ : conn(nullptr)
+ , autoClose(true)
+{
+ auto logger(libdnf::Log::getLogger());
+
+ if (path == ":memory:") {
+ // connect to an in-memory database as requested
+ conn = std::make_shared<SQLite3>(path);
+ Transformer::createDatabase(conn);
+ return;
+ }
+
+ bool path_exists;
+ try {
+ path_exists = pathExistsOrException(path.c_str());
+ } catch (Error & e) {
+ // pathExistsOrException() threw an exception, most likely a permission error
+ // -> use an in-memory fallback
+ conn = std::make_shared<SQLite3>(":memory:");
+ Transformer::createDatabase(conn);
+ logger->error(tfm::format(
+ "History database is not readable, using in-memory database instead: %s",
+ e.what())
+ );
+ return;
+ }
+
+ if (path_exists) {
+ if (geteuid() == 0) {
+ // database exists, running under root
+ try {
+ conn = std::make_shared<SQLite3>(path);
+ // execute an update to detect if the database is writable
+ conn->exec("BEGIN; UPDATE config SET value='test' WHERE key='test'; ROLLBACK;");
+ } catch (SQLite3::Error & ex) {
+ // root must have the database writable -> log and re-throw the exception
+ logger->error(tfm::format("History database is not writable: %s", ex.what()));
+ throw;
+ }
+ } else {
+ // database exists, running under unprivileged user
+ try {
+ conn = std::make_shared<SQLite3>(path);
+ // execute a select to detect if the database is readable
+ conn->exec("SELECT * FROM config WHERE key='test'");
+ } catch (SQLite3::Error & ex) {
+ // unpriviledged user may have insufficient permissions to open the database -> in-memory fallback
+ conn = std::make_shared<SQLite3>(":memory:");
+ Transformer::createDatabase(conn);
+ logger->error(tfm::format("History database is not readable, using in-memory database instead: %s", ex.what()));
+ }
+ }
+ } else {
+ if (geteuid() == 0) {
+ // database doesn't exist, running under root
+ // create a new database and migrate old data
+
+ // extract persistdir from path - "/var/lib/dnf/"
+ auto found = path.find_last_of("/");
+ try {
+ Transformer transformer(path.substr(0, found), path);
+ transformer.transform();
+ conn = std::make_shared<SQLite3>(path);
+ } catch (SQLite3::Error & ex) {
+ // root must have the database writable -> log and re-throw the exception
+ logger->error(tfm::format("History database cannot be created: %s", ex.what()));
+ throw;
+ }
+ } else {
+ try {
+ // database doesn't exist, running under unprivileged user
+ // connect to a new database and initialize it; old data is not migrated
+ conn = std::make_shared<SQLite3>(path);
+ Transformer::createDatabase(conn);
+ } catch (SQLite3::Error & ex) {
+ // unpriviledged user may have insufficient permissions to create the database -> in-memory fallback
+ conn = std::make_shared<SQLite3>(":memory:");
+ Transformer::createDatabase(conn);
+ logger->error(tfm::format("History database cannot be created, using in-memory database instead: %s", ex.what()));
+ }
+ }
+ }
+ Transformer::migrateSchema(conn);
+}
+
+void
+Swdb::resetDatabase()
+{
+ conn->close();
+ if (pathExists(getPath().c_str())) {
+ remove(getPath().c_str());
+ }
+ conn->open();
+ Transformer::createDatabase(conn);
+}
+
+void
+Swdb::closeDatabase()
+{
+ conn->close();
+}
+
+Swdb::~Swdb()
+{
+ if (autoClose) {
+ try {
+ closeDatabase();
+ } catch(const std::exception &){}
+ }
+}
+
+void
+Swdb::initTransaction()
+{
+ if (transactionInProgress) {
+ throw std::logic_error(_("In progress"));
+ }
+ transactionInProgress = std::make_shared< swdb_private::Transaction >(conn);
+ itemsInProgress.clear();
+}
+
+int64_t
+Swdb::beginTransaction(int64_t dtBegin,
+ std::string rpmdbVersionBegin,
+ std::string cmdline,
+ uint32_t userId,
+ std::string comment)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+
+ // begin transaction
+ transactionInProgress->setDtBegin(dtBegin);
+ transactionInProgress->setRpmdbVersionBegin(rpmdbVersionBegin);
+ transactionInProgress->setCmdline(cmdline);
+ transactionInProgress->setUserId(userId);
+ transactionInProgress->setComment(comment);
+ transactionInProgress->begin();
+
+ // save rpm items to map to resolve RPM callbacks
+ for (auto item : transactionInProgress->getItems()) {
+ auto transItem = item->getItem();
+ if (transItem->getItemType() != ItemType::RPM) {
+ continue;
+ }
+ auto rpmItem = std::dynamic_pointer_cast< RPMItem >(transItem);
+ itemsInProgress[rpmItem->getNEVRA()] = item;
+ }
+
+ return transactionInProgress->getId();
+}
+
+int64_t
+Swdb::endTransaction(int64_t dtEnd, std::string rpmdbVersionEnd, TransactionState state)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+ transactionInProgress->setDtEnd(dtEnd);
+ transactionInProgress->setRpmdbVersionEnd(rpmdbVersionEnd);
+ transactionInProgress->finish(state);
+ return transactionInProgress->getId();
+}
+
+int64_t
+Swdb::closeTransaction()
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+ int64_t result = transactionInProgress->getId();
+ transactionInProgress = std::unique_ptr< swdb_private::Transaction >(nullptr);
+ itemsInProgress.clear();
+ return result;
+}
+
+
+TransactionItemPtr
+Swdb::addItem(std::shared_ptr< Item > item,
+ const std::string &repoid,
+ TransactionItemAction action,
+ TransactionItemReason reason)
+// std::shared_ptr<TransactionItem> replacedBy)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+ // auto replacedBy = std::make_shared<TransactionItem>(nullptr);
+ return transactionInProgress->addItem(item, repoid, action, reason);
+}
+
+void
+Swdb::setItemDone(const std::string &nevra)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("No transaction in progress"));
+ }
+ auto item = itemsInProgress[nevra];
+ item->setState(TransactionItemState::DONE);
+ item->saveState();
+}
+
+TransactionItemReason
+Swdb::resolveRPMTransactionItemReason(const std::string &name,
+ const std::string &arch,
+ int64_t maxTransactionId)
+{
+ // TODO:
+ // -1: latest
+ // -2: latest and lastTransaction data in memory
+ if (maxTransactionId == -2 && transactionInProgress != nullptr) {
+ for (auto i : transactionInProgress->getItems()) {
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(i->getItem());
+ if (!rpm) {
+ continue;
+ }
+ if (rpm->getName() == name && rpm->getArch() == arch) {
+ return i->getReason();
+ }
+ }
+ }
+
+ return RPMItem::resolveTransactionItemReason(conn, name, arch, maxTransactionId);
+}
+
+const std::string
+Swdb::getRPMRepo(const std::string &nevra)
+{
+ Nevra nevraObject;
+ if (!nevraObject.parse(nevra.c_str(), HY_FORM_NEVRA)) {
+ return "";
+ }
+ // TODO: hy_nevra_possibility should set epoch to 0 if epoch is not specified
+ // and HY_FORM_NEVRA is used
+ if (nevraObject.getEpoch() < 0) {
+ nevraObject.setEpoch(0);
+ }
+
+ const char *sql = R"**(
+ SELECT
+ repo.repoid as repoid
+ FROM
+ trans_item ti
+ JOIN
+ rpm USING (item_id)
+ JOIN
+ repo ON ti.repo_id == repo.id
+ WHERE
+ ti.action not in (3, 5, 7, 10)
+ AND rpm.name = ?
+ AND rpm.epoch = ?
+ AND rpm.version = ?
+ AND rpm.release = ?
+ AND rpm.arch = ?
+ ORDER BY
+ ti.id DESC
+ LIMIT 1;
+ )**";
+ // TODO: where trans.done != 0
+ SQLite3::Query query(*conn, sql);
+ query.bindv(nevraObject.getName(),
+ nevraObject.getEpoch(),
+ nevraObject.getVersion(),
+ nevraObject.getRelease(),
+ nevraObject.getArch());
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto repoid = query.get< std::string >("repoid");
+ return repoid;
+ }
+ return "";
+}
+
+TransactionItemPtr
+Swdb::getRPMTransactionItem(const std::string &nevra)
+{
+ return RPMItem::getTransactionItem(conn, nevra);
+}
+
+TransactionPtr
+Swdb::getLastTransaction()
+{
+ const char *sql = R"**(
+ SELECT
+ id
+ FROM
+ trans
+ ORDER BY
+ id DESC
+ LIMIT 1
+ )**";
+ SQLite3::Statement query(*conn, sql);
+ if (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto transId = query.get< int64_t >(0);
+ auto transaction = std::make_shared< Transaction >(conn, transId);
+ return transaction;
+ }
+ return nullptr;
+}
+
+std::vector< TransactionPtr >
+Swdb::listTransactions()
+{
+ const char *sql = R"**(
+ SELECT
+ id
+ FROM
+ trans
+ ORDER BY
+ id
+ )**";
+ SQLite3::Statement query(*conn, sql);
+ std::vector< TransactionPtr > result;
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto transId = query.get< int64_t >(0);
+ auto transaction = std::make_shared< Transaction >(conn, transId);
+ result.push_back(transaction);
+ }
+ return result;
+}
+
+void
+Swdb::setReleasever(std::string value)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+ transactionInProgress->setReleasever(value);
+}
+
+
+void
+Swdb::addConsoleOutputLine(int fileDescriptor, std::string line)
+{
+ if (!transactionInProgress) {
+ throw std::logic_error(_("Not in progress"));
+ }
+ transactionInProgress->addConsoleOutputLine(fileDescriptor, line);
+}
+
+TransactionItemPtr
+Swdb::getCompsGroupItem(const std::string &groupid)
+{
+ return CompsGroupItem::getTransactionItem(conn, groupid);
+}
+
+std::vector< TransactionItemPtr >
+Swdb::getCompsGroupItemsByPattern(const std::string &pattern)
+{
+ return CompsGroupItem::getTransactionItemsByPattern(conn, pattern);
+}
+
+std::vector< std::string >
+Swdb::getPackageCompsGroups(const std::string &packageName)
+{
+ const char *sql_all_groups = R"**(
+ SELECT DISTINCT
+ g.groupid
+ FROM
+ comps_group g
+ JOIN
+ comps_group_package p ON p.group_id = g.item_id
+ WHERE
+ p.name = ?
+ AND p.installed = 1
+ ORDER BY
+ g.groupid
+ )**";
+
+ const char *sql_trans_items = R"**(
+ SELECT
+ ti.action as action,
+ ti.reason as reason,
+ i.item_id as group_id
+ FROM
+ trans_item ti
+ JOIN
+ comps_group i USING (item_id)
+ JOIN
+ trans t ON ti.trans_id = t.id
+ WHERE
+ t.state = 1
+ AND ti.action not in (3, 5, 7)
+ AND i.groupid = ?
+ ORDER BY
+ ti.trans_id DESC
+ LIMIT 1
+ )**";
+
+ const char *sql_group_package = R"**(
+ SELECT
+ p.name
+ FROM
+ comps_group_package p
+ WHERE
+ p.group_id = ?
+ AND p.installed = 1
+ )**";
+
+ std::vector< std::string > result;
+
+ // list all relevant groups
+ SQLite3::Query query_all_groups(*conn, sql_all_groups);
+ query_all_groups.bindv(packageName);
+
+ while (query_all_groups.step() == SQLite3::Statement::StepResult::ROW) {
+ auto groupid = query_all_groups.get< std::string >("groupid");
+ SQLite3::Query query_trans_items(*conn, sql_trans_items);
+ query_trans_items.bindv(groupid);
+ if (query_trans_items.step() == SQLite3::Statement::StepResult::ROW) {
+ auto action =
+ static_cast< TransactionItemAction >(query_trans_items.get< int64_t >("action"));
+ // if the last record is group removal, skip
+ if (action == TransactionItemAction::REMOVE) {
+ continue;
+ }
+ auto groupId = query_trans_items.get< int64_t >("group_id");
+ SQLite3::Query query_group_package(*conn, sql_group_package);
+ query_group_package.bindv(groupId);
+ if (query_group_package.step() == SQLite3::Statement::StepResult::ROW) {
+ result.push_back(groupid);
+ }
+ }
+ }
+ return result;
+}
+
+std::vector< std::string >
+Swdb::getCompsGroupEnvironments(const std::string &groupId)
+{
+ const char *sql_all_environments = R"**(
+ SELECT DISTINCT
+ e.environmentid
+ FROM
+ comps_environment e
+ JOIN
+ comps_environment_group g ON g.environment_id = e.item_id
+ WHERE
+ g.groupid = ?
+ AND g.installed = 1
+ ORDER BY
+ e.environmentid
+ )**";
+
+ const char *sql_trans_items = R"**(
+ SELECT
+ ti.action as action,
+ ti.reason as reason,
+ i.item_id as environment_id
+ FROM
+ trans_item ti
+ JOIN
+ comps_environment i USING (item_id)
+ JOIN
+ trans t ON ti.trans_id = t.id
+ WHERE
+ t.state = 1
+ AND ti.action not in (3, 5, 7)
+ AND i.environmentid = ?
+ ORDER BY
+ ti.trans_id DESC
+ LIMIT 1
+ )**";
+
+ const char *sql_environment_group = R"**(
+ SELECT
+ g.groupid
+ FROM
+ comps_environment_group g
+ WHERE
+ g.environment_id = ?
+ AND g.installed = 1
+ )**";
+
+ std::vector< std::string > result;
+
+ // list all relevant groups
+ SQLite3::Query query_all_environments(*conn, sql_all_environments);
+ query_all_environments.bindv(groupId);
+
+ while (query_all_environments.step() == SQLite3::Statement::StepResult::ROW) {
+ auto envid = query_all_environments.get< std::string >("environmentid");
+ SQLite3::Query query_trans_items(*conn, sql_trans_items);
+ query_trans_items.bindv(envid);
+ if (query_trans_items.step() == SQLite3::Statement::StepResult::ROW) {
+ auto action =
+ static_cast< TransactionItemAction >(query_trans_items.get< int64_t >("action"));
+ // if the last record is group removal, skip
+ if (action == TransactionItemAction::REMOVE) {
+ continue;
+ }
+ auto envId = query_trans_items.get< int64_t >("environment_id");
+ SQLite3::Query query_environment_group(*conn, sql_environment_group);
+ query_environment_group.bindv(envId);
+ if (query_environment_group.step() == SQLite3::Statement::StepResult::ROW) {
+ result.push_back(envid);
+ }
+ }
+ }
+ return result;
+}
+
+TransactionItemPtr
+Swdb::getCompsEnvironmentItem(const std::string &envid)
+{
+ return CompsEnvironmentItem::getTransactionItem(conn, envid);
+}
+
+std::vector< TransactionItemPtr >
+Swdb::getCompsEnvironmentItemsByPattern(const std::string &pattern)
+{
+ return CompsEnvironmentItem::getTransactionItemsByPattern(conn, pattern);
+}
+
+RPMItemPtr
+Swdb::createRPMItem()
+{
+ return std::make_shared< RPMItem >(conn);
+}
+
+CompsEnvironmentItemPtr
+Swdb::createCompsEnvironmentItem()
+{
+ return std::make_shared< CompsEnvironmentItem >(conn);
+}
+
+CompsGroupItemPtr
+Swdb::createCompsGroupItem()
+{
+ return std::make_shared< CompsGroupItem >(conn);
+}
+
+/**
+ * Filter unneeded packages from pool
+ *
+ * \return list of user installed package IDs
+ */
+void
+Swdb::filterUserinstalled(PackageSet & installed) const
+{
+ Pool * pool = dnf_sack_get_pool(installed.getSack());
+
+ // iterate over solvables
+ Id id = -1;
+ while ((id = installed.next(id)) != -1) {
+
+ Solvable *s = pool_id2solvable(pool, id);
+ const char *name = pool_id2str(pool, s->name);
+ const char *arch = pool_id2str(pool, s->arch);
+
+ auto reason = RPMItem::resolveTransactionItemReason(conn, name, arch, -1);
+ // if not dep or weak, than consider it user installed
+ if (reason == TransactionItemReason::DEPENDENCY ||
+ reason == TransactionItemReason::WEAK_DEPENDENCY) {
+ installed.remove(id);
+ }
+ }
+}
+
+std::vector< int64_t >
+Swdb::searchTransactionsByRPM(const std::vector< std::string > &patterns)
+{
+ return RPMItem::searchTransactions(conn, patterns);
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_SWDB_HPP
+#define LIBDNF_TRANSACTION_SWDB_HPP
+
+#include <map>
+#include <memory>
+#include <solv/pooltypes.h>
+#include <sys/stat.h>
+#include <vector>
+
+namespace libdnf {
+struct Swdb;
+class Transformer;
+}
+
+#include "../hy-types.h"
+#include "../sack/query.hpp"
+#include "../sack/packageset.hpp"
+#include "../utils/sqlite3/Sqlite3.hpp"
+
+#include "CompsGroupItem.hpp"
+#include "Transaction.hpp"
+#include "TransactionItem.hpp"
+#include "private/Transaction.hpp"
+
+namespace libdnf {
+
+struct Swdb {
+public:
+ explicit Swdb(SQLite3Ptr conn);
+ explicit Swdb(const std::string &path);
+ ~Swdb();
+
+ SQLite3Ptr getConn() { return conn; }
+
+ // Database
+ // FIXME load this from conf
+ static constexpr const char *defaultPath = "/var/lib/dnf/history.sqlite";
+ static constexpr const char *defaultDatabaseName = "history.sqlite";
+
+ const std::string &getPath() { return conn->getPath(); }
+ void resetDatabase();
+ void closeDatabase();
+
+ // Transaction in progress
+ void initTransaction();
+ int64_t beginTransaction(int64_t dtBegin,
+ std::string rpmdbVersionBegin,
+ std::string cmdline,
+ uint32_t userId,
+ std::string comment = std::string());
+ int64_t endTransaction(int64_t dtEnd, std::string rpmdbVersionEnd, TransactionState state);
+ int64_t closeTransaction();
+ // TODO:
+ std::vector< TransactionItemPtr > getItems() { return transactionInProgress->getItems(); }
+
+ TransactionPtr getLastTransaction();
+ std::vector< TransactionPtr >
+ listTransactions(); // std::vector<long long> transactionIds);
+
+ TransactionPtr getCurrent() { return std::dynamic_pointer_cast<Transaction>(transactionInProgress); }
+
+ // TransactionItems
+ TransactionItemPtr addItem(ItemPtr item,
+ const std::string &repoid,
+ TransactionItemAction action,
+ TransactionItemReason reason);
+ // std::shared_ptr<TransactionItem> replacedBy);
+
+ // TODO: remove; TransactionItem states are saved on transaction save
+ void setItemDone(const std::string &nevra);
+
+ // Item: constructors
+ RPMItemPtr createRPMItem();
+ CompsGroupItemPtr createCompsGroupItem();
+ CompsEnvironmentItemPtr createCompsEnvironmentItem();
+
+ // Item: RPM
+ TransactionItemReason resolveRPMTransactionItemReason(const std::string &name,
+ const std::string &arch,
+ int64_t maxTransactionId);
+ const std::string getRPMRepo(const std::string &nevra);
+ TransactionItemPtr getRPMTransactionItem(const std::string &nevra);
+ std::vector< int64_t > searchTransactionsByRPM(const std::vector< std::string > &patterns);
+
+ // Item: CompsGroup
+ TransactionItemPtr getCompsGroupItem(const std::string &groupid);
+ std::vector< TransactionItemPtr > getCompsGroupItemsByPattern(const std::string &pattern);
+ std::vector< std::string > getPackageCompsGroups(const std::string &packageName);
+
+ // Item: CompsEnvironment
+ TransactionItemPtr getCompsEnvironmentItem(const std::string &envid);
+ std::vector< TransactionItemPtr > getCompsEnvironmentItemsByPattern(const std::string &pattern);
+ std::vector< std::string > getCompsGroupEnvironments(const std::string &groupId);
+
+ // misc
+ void setReleasever(std::string value);
+ void addConsoleOutputLine(int fileDescriptor, std::string line);
+
+ /**
+ * @brief Remove packages from PackageSet that were installed as Dependency or WEAK_DEPENDENCY
+ */
+ void filterUserinstalled(PackageSet & installed) const;
+
+protected:
+ friend class Transformer;
+
+ explicit Swdb(SQLite3Ptr conn, bool autoClose);
+ SQLite3Ptr conn;
+ bool autoClose;
+ std::shared_ptr< swdb_private::Transaction > transactionInProgress = nullptr;
+ std::map< std::string, TransactionItemPtr > itemsInProgress;
+
+private:
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_SWDB_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Transaction.hpp"
+#include "CompsEnvironmentItem.hpp"
+#include "CompsGroupItem.hpp"
+#include "RPMItem.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+Transaction::Transaction(SQLite3Ptr conn, int64_t pk)
+ : conn{conn}
+{
+ dbSelect(pk);
+}
+
+Transaction::Transaction(SQLite3Ptr conn)
+ : conn{conn}
+{
+}
+
+bool
+Transaction::operator==(const Transaction &other) const
+{
+ return getId() == other.getId() && getDtBegin() == other.getDtBegin() &&
+ getRpmdbVersionBegin() == other.getRpmdbVersionBegin();
+}
+
+/**
+ * Compare two transactions on:
+ * transaction ID
+ * begin timestamp
+ * packages in the system at the time of transaction
+ * \param other transaction to compare with
+ * \return true if other transaction is older
+ */
+bool
+Transaction::operator<(const Transaction &other) const
+{
+ return getId() > other.getId() || getDtBegin() > other.getDtBegin() ||
+ getRpmdbVersionBegin() > other.getRpmdbVersionBegin();
+}
+
+/**
+ * \param other transaction to compare with
+ * \return true if other transaction is newer
+ */
+bool
+Transaction::operator>(const Transaction &other) const
+{
+ return getId() < other.getId() || getDtBegin() < other.getDtBegin() ||
+ getRpmdbVersionBegin() < other.getRpmdbVersionBegin();
+}
+
+void
+Transaction::dbSelect(int64_t pk)
+{
+ const char *sql =
+ "SELECT "
+ " dt_begin, "
+ " dt_end, "
+ " rpmdb_version_begin, "
+ " rpmdb_version_end, "
+ " releasever, "
+ " user_id, "
+ " cmdline, "
+ " state, "
+ " comment "
+ "FROM "
+ " trans "
+ "WHERE "
+ " id = ?";
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(pk);
+ query.step();
+
+ id = pk;
+ dtBegin = query.get< int >("dt_begin");
+ dtEnd = query.get< int >("dt_end");
+ rpmdbVersionBegin = query.get< std::string >("rpmdb_version_begin");
+ rpmdbVersionEnd = query.get< std::string >("rpmdb_version_end");
+ releasever = query.get< std::string >("releasever");
+ userId = query.get< uint32_t >("user_id");
+ cmdline = query.get< std::string >("cmdline");
+ state = static_cast< TransactionState >(query.get< int >("state"));
+ comment = query.get< std::string >("comment");
+}
+
+/**
+ * Loader for the transaction items.
+ * \return list of transaction items associated with the transaction
+ */
+std::vector< TransactionItemPtr >
+Transaction::getItems()
+{
+ std::vector< TransactionItemPtr > result;
+ auto rpms = RPMItem::getTransactionItems(conn, getId());
+ result.insert(result.end(), rpms.begin(), rpms.end());
+
+ auto comps_groups = CompsGroupItem::getTransactionItems(conn, getId());
+ result.insert(result.end(), comps_groups.begin(), comps_groups.end());
+
+ auto comps_environments = CompsEnvironmentItem::getTransactionItems(conn, getId());
+ result.insert(result.end(), comps_environments.begin(), comps_environments.end());
+
+ return result;
+}
+
+/**
+ * Load list of software performed with for current transaction from the database.
+ * Transaction has to be saved in advance, otherwise empty list will be returned.
+ * \return list of RPMItem objects that performed the transaction
+ */
+const std::set< std::shared_ptr< RPMItem > >
+Transaction::getSoftwarePerformedWith() const
+{
+ const char *sql = R"**(
+ SELECT
+ item_id
+ FROM
+ trans_with
+ WHERE
+ trans_id = ?
+ )**";
+
+ std::set< std::shared_ptr< RPMItem > > software;
+
+ SQLite3::Query query(*conn.get(), sql);
+ query.bindv(getId());
+
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ software.insert(std::make_shared< RPMItem >(conn, query.get< int64_t >("item_id")));
+ }
+
+ return software;
+}
+
+std::vector< std::pair< int, std::string > >
+Transaction::getConsoleOutput() const
+{
+ const char *sql = R"**(
+ SELECT
+ file_descriptor,
+ line
+ FROM
+ console_output
+ WHERE
+ trans_id = ?
+ ORDER BY
+ id
+ )**";
+ SQLite3::Query query(*conn, sql);
+ query.bindv(getId());
+ std::vector< std::pair< int, std::string > > result;
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto fileDescriptor = query.get< int >("file_descriptor");
+ auto line = query.get< std::string >("line");
+ result.push_back(std::make_pair(fileDescriptor, line));
+ }
+ return result;
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSACTION_HPP
+#define LIBDNF_TRANSACTION_TRANSACTION_HPP
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "../utils/sqlite3/Sqlite3.hpp"
+
+namespace libdnf {
+class Transaction;
+typedef std::shared_ptr< Transaction > TransactionPtr;
+}
+
+#include "Item.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+class Transaction {
+public:
+ // load from db
+ Transaction(SQLite3Ptr conn, int64_t pk);
+ virtual ~Transaction() = default;
+
+ bool operator==(const Transaction &other) const;
+ bool operator<(const Transaction &other) const;
+ bool operator>(const Transaction &other) const;
+
+ int64_t getId() const noexcept { return id; }
+ int64_t getDtBegin() const noexcept { return dtBegin; }
+ int64_t getDtEnd() const noexcept { return dtEnd; }
+ const std::string &getRpmdbVersionBegin() const noexcept { return rpmdbVersionBegin; }
+ const std::string &getRpmdbVersionEnd() const noexcept { return rpmdbVersionEnd; }
+ const std::string &getReleasever() const noexcept { return releasever; }
+ uint32_t getUserId() const noexcept { return userId; }
+ const std::string &getCmdline() const noexcept { return cmdline; }
+ TransactionState getState() const noexcept { return state; }
+ const std::string &getComment() const noexcept { return comment; }
+
+ virtual std::vector< TransactionItemPtr > getItems();
+ const std::set< std::shared_ptr< RPMItem > > getSoftwarePerformedWith() const;
+ std::vector< std::pair< int, std::string > > getConsoleOutput() const;
+
+protected:
+ explicit Transaction(SQLite3Ptr conn);
+ void dbSelect(int64_t transaction_id);
+ std::set< std::shared_ptr< RPMItem > > softwarePerformedWith;
+
+ friend class TransactionItem;
+ SQLite3Ptr conn;
+
+ int64_t id = 0;
+ int64_t dtBegin = 0;
+ int64_t dtEnd = 0;
+ std::string rpmdbVersionBegin;
+ std::string rpmdbVersionEnd;
+ // TODO: move to a new "vars" table?
+ std::string releasever;
+ uint32_t userId = 0;
+ std::string cmdline;
+ TransactionState state = TransactionState::UNKNOWN;
+ std::string comment;
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_TRANSACTION_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "../utils/bgettext/bgettext-lib.h"
+
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+// TODO: translations
+static const std::map< TransactionItemAction, std::string > transactionItemActionName = {
+ {TransactionItemAction::INSTALL, "Install"},
+ {TransactionItemAction::DOWNGRADE, "Downgrade"},
+ {TransactionItemAction::DOWNGRADED, "Downgraded"},
+ {TransactionItemAction::OBSOLETE, "Obsolete"},
+ {TransactionItemAction::OBSOLETED, "Obsoleted"},
+ {TransactionItemAction::UPGRADE, "Upgrade"},
+ {TransactionItemAction::UPGRADED, "Upgraded"},
+ {TransactionItemAction::REMOVE, "Removed"},
+ {TransactionItemAction::REINSTALL, "Reinstall"},
+ {TransactionItemAction::REINSTALLED, "Reinstalled"},
+ {TransactionItemAction::REASON_CHANGE, "Reason Change"},
+};
+
+static const std::map< TransactionItemAction, std::string > transactionItemActionShort = {
+ {TransactionItemAction::INSTALL, "I"},
+ {TransactionItemAction::DOWNGRADE, "D"},
+ {TransactionItemAction::DOWNGRADED, "D"},
+ {TransactionItemAction::OBSOLETE, "O"},
+ {TransactionItemAction::OBSOLETED, "O"},
+ {TransactionItemAction::UPGRADE, "U"},
+ {TransactionItemAction::UPGRADED, "U"},
+ // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
+ {TransactionItemAction::REMOVE, "E"},
+ {TransactionItemAction::REINSTALL, "R"},
+ {TransactionItemAction::REINSTALLED, "R"},
+ {TransactionItemAction::REASON_CHANGE, "C"},
+};
+
+/*
+static const std::map<std::string, TransactionItemReason> nameTransactionItemReason = {
+ {, "I"},
+ {TransactionItemAction::DOWNGRADE, "D"},
+ {TransactionItemAction::DOWNGRADED, "D"},
+ {TransactionItemAction::OBSOLETE, "O"},
+ {TransactionItemAction::OBSOLETED, "O"},
+ {TransactionItemAction::UPGRADE, "U"},
+ {TransactionItemAction::UPGRADED, "U"},
+ // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
+ {TransactionItemAction::REMOVE, "E"},
+ {TransactionItemAction::REINSTALL, "R"},
+};
+TransactionItemReason to_TransactionItemReason(const std::string & s) {
+ return
+*/
+
+const std::string &
+TransactionItemBase::getActionName()
+{
+ return transactionItemActionName.at(getAction());
+}
+
+const std::string &
+TransactionItemBase::getActionShort()
+{
+ return transactionItemActionShort.at(getAction());
+}
+
+TransactionItem::TransactionItem(Transaction *trans)
+ : trans(trans)
+ , transID(0)
+ , conn(trans->conn)
+{
+}
+
+bool
+TransactionItemBase::isForwardAction() const
+{
+ switch (action) {
+ case TransactionItemAction::INSTALL:
+ case TransactionItemAction::DOWNGRADE:
+ case TransactionItemAction::OBSOLETE:
+ case TransactionItemAction::UPGRADE:
+ case TransactionItemAction::REINSTALL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool
+TransactionItemBase::isBackwardAction() const
+{
+ switch (action) {
+ case TransactionItemAction::REMOVE:
+ case TransactionItemAction::DOWNGRADED:
+ case TransactionItemAction::OBSOLETED:
+ case TransactionItemAction::UPGRADED:
+ case TransactionItemAction::REINSTALLED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+TransactionItem::TransactionItem(SQLite3Ptr conn, int64_t transID)
+ : trans(nullptr)
+ , transID(transID)
+ , conn(conn)
+{
+}
+
+void
+TransactionItem::save()
+{
+ getItem()->save();
+ if (getId() == 0) {
+ dbInsert();
+ } else {
+ dbUpdate();
+ }
+}
+
+void
+TransactionItem::dbInsert()
+{
+ if (trans == nullptr) {
+ throw std::runtime_error(
+ _("Attempt to insert transaction item into completed transaction"));
+ }
+
+ const char *sql = R"**(
+ INSERT INTO
+ trans_item (
+ id,
+ trans_id,
+ item_id,
+ repo_id,
+ action,
+ reason,
+ state
+ )
+ VALUES
+ (null, ?, ?, ?, ?, ?, ?)
+ )**";
+
+ // save the transaction item
+ SQLite3::Statement query(*(conn.get()), sql);
+ query.bindv(trans->getId(),
+ getItem()->getId(),
+ swdb_private::Repo::getCached(conn, getRepoid())->getId(),
+ static_cast< int >(getAction()),
+ static_cast< int >(getReason()),
+ static_cast< int >(getState()));
+ query.step();
+ setId(conn->lastInsertRowID());
+}
+
+void
+TransactionItem::saveReplacedBy()
+{
+ if (replacedBy.empty()) {
+ return;
+ }
+ const char *sql = "INSERT OR REPLACE INTO item_replaced_by VALUES (?, ?)";
+ SQLite3::Statement replacedByQuery(*(conn.get()), sql);
+ bool first = true;
+ for (const auto &newItem : replacedBy) {
+ if (!first) {
+ // reset the prepared statement, so it can be executed again
+ replacedByQuery.reset();
+ }
+ replacedByQuery.bindv(getId(), newItem->getId());
+ replacedByQuery.step();
+ first = false;
+ }
+}
+
+void
+TransactionItem::saveState()
+{
+ const char *sql = R"**(
+ UPDATE
+ trans_item
+ SET
+ state = ?
+ WHERE
+ id = ?
+ )**";
+
+ SQLite3::Statement query(*conn, sql);
+ query.bindv(static_cast< int >(getState()), getId());
+ query.step();
+}
+
+void
+TransactionItem::dbUpdate()
+{
+ if (trans == nullptr) {
+ throw std::runtime_error(_("Attempt to update transaction item in completed transaction"));
+ }
+
+ const char *sql = R"**(
+ UPDATE
+ trans_item
+ SET
+ trans_id=?,
+ item_id=?,
+ repo_id=?,
+ action=?,
+ reason=?,
+ state=?
+ WHERE
+ id = ?
+ )**";
+
+ SQLite3::Statement query(*(conn.get()), sql);
+ query.bindv(trans->getId(),
+ getItem()->getId(),
+ swdb_private::Repo::getCached(trans->conn, getRepoid())->getId(),
+ static_cast< int >(getAction()),
+ static_cast< int >(getReason()),
+ static_cast< int >(getState()),
+ getId());
+ query.step();
+}
+
+uint32_t
+TransactionItem::getInstalledBy() const {
+ if (!trans) {
+ // null pointer -> create a local instance to return the user id
+ Transaction t(conn, transID);
+ return t.getUserId();
+ }
+ return trans->getUserId();
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSACTIONITEM_HPP
+#define LIBDNF_TRANSACTION_TRANSACTIONITEM_HPP
+
+#include <memory>
+#include <string>
+
+#include "../utils/sqlite3/Sqlite3.hpp"
+
+namespace libdnf {
+class TransactionItem;
+typedef std::shared_ptr< TransactionItem > TransactionItemPtr;
+}
+
+#include "Item.hpp"
+#include "CompsEnvironmentItem.hpp"
+#include "CompsGroupItem.hpp"
+#include "RPMItem.hpp"
+#include "private/Repo.hpp"
+#include "Transaction.hpp"
+#include "Types.hpp"
+
+namespace libdnf {
+
+class TransactionItemBase {
+public:
+ virtual ~TransactionItemBase() = default;
+
+ ItemPtr getItem() const noexcept { return item; }
+ void setItem(ItemPtr value) { item = value; }
+
+ // typed items - workaround for lack of shared_ptr<> downcast support in SWIG
+ CompsEnvironmentItemPtr getCompsEnvironmentItem() const noexcept
+ {
+ return std::dynamic_pointer_cast< CompsEnvironmentItem >(item);
+ }
+ CompsGroupItemPtr getCompsGroupItem() const noexcept
+ {
+ return std::dynamic_pointer_cast< CompsGroupItem >(item);
+ }
+ RPMItemPtr getRPMItem() const noexcept { return std::dynamic_pointer_cast< RPMItem >(item); }
+
+ const std::string &getRepoid() const noexcept { return repoid; }
+ void setRepoid(const std::string &value) { repoid = value; }
+
+ TransactionItemAction getAction() const noexcept { return action; }
+ void setAction(TransactionItemAction value) { action = value; }
+
+ TransactionItemReason getReason() const noexcept { return reason; }
+ void setReason(TransactionItemReason value) { reason = value; }
+
+ const std::string &getActionName();
+ const std::string &getActionShort();
+
+ TransactionItemState getState() const noexcept { return state; }
+ void setState(TransactionItemState value) { state = value; }
+
+ /**
+ * @brief Has the item appeared on the system during the transaction?
+ *
+ * @return bool
+ */
+ bool isForwardAction() const;
+
+ /**
+ * @brief Has the item got removed from the system during the transaction?
+ *
+ * @return bool
+ */
+ bool isBackwardAction() const;
+
+protected:
+ ItemPtr item;
+ std::string repoid;
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::UNKNOWN;
+ TransactionItemState state = TransactionItemState::UNKNOWN;
+};
+
+typedef std::shared_ptr< TransactionItemBase > TransactionItemBasePtr;
+
+class TransactionItem : public TransactionItemBase {
+public:
+ explicit TransactionItem(Transaction *trans);
+
+ TransactionItem(SQLite3Ptr conn, int64_t transID);
+ virtual ~TransactionItem() = default;
+
+ int64_t getId() const noexcept { return id; }
+ void setId(int64_t value) { id = value; }
+
+ uint32_t getInstalledBy() const;
+
+ // int64_t getTransactionId() const noexcept { return trans.getId(); }
+
+ const std::vector< TransactionItemPtr > &getReplacedBy() const noexcept { return replacedBy; }
+ void addReplacedBy(TransactionItemPtr value) { if (value) replacedBy.push_back(value); }
+
+ void save();
+ void saveReplacedBy();
+ void saveState();
+
+ std::size_t getHash() { return reinterpret_cast< std::size_t >(this); }
+ bool operator==(TransactionItem & other) { return (other.getHash() == getHash()); }
+ bool operator==(TransactionItemPtr other) { return (other->getHash() == getHash()); }
+
+ // needed for sorting a list of transaction items in Python
+ // TODO: consider replacing trivial string comparison with something better
+ bool operator<(TransactionItem & other) { return (getItem()->toStr() < other.getItem()->toStr()); }
+ bool operator<(TransactionItemPtr other) { return (getItem()->toStr() < other->getItem()->toStr()); }
+
+protected:
+ int64_t id = 0;
+ Transaction *trans;
+
+ const int64_t transID;
+ SQLite3Ptr conn;
+
+ // TODO: replace with objects? it's just repoid, probably not necessary
+ std::vector< TransactionItemPtr > replacedBy;
+
+ void dbInsert();
+ void dbUpdate();
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_TRANSACTIONITEM_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "TransactionItemReason.hpp"
+
+#include <map>
+#include <stdexcept>
+
+
+namespace libdnf {
+
+static const std::map<TransactionItemReason, std::string> transactionItemReasonName = {
+ {TransactionItemReason::UNKNOWN, "unknown"},
+ {TransactionItemReason::DEPENDENCY, "dependency"},
+ {TransactionItemReason::USER, "user"},
+ {TransactionItemReason::CLEAN, "clean"},
+ {TransactionItemReason::WEAK_DEPENDENCY, "weak-dependency"},
+ {TransactionItemReason::GROUP, "group"},
+};
+
+const std::string &
+TransactionItemReasonToString(TransactionItemReason reason)
+{
+ try {
+ return transactionItemReasonName.at(reason);
+ } catch (std::out_of_range & e) {
+ throw std::out_of_range("Transaction Item Reason ID \"" +
+ std::to_string(static_cast<int>(reason)) + "\" not found.");
+ }
+}
+
+TransactionItemReason StringToTransactionItemReason(const std::string & str)
+{
+ for (auto it = transactionItemReasonName.begin(); it != transactionItemReasonName.end(); ++it) {
+ if (it->second == str) {
+ return it->first;
+ }
+ }
+
+ throw std::out_of_range("Transaction Item Reason \"" + str + "\" not found.");
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSACTIONITEMREASON_HPP
+#define LIBDNF_TRANSACTION_TRANSACTIONITEMREASON_HPP
+
+
+#include <string>
+
+
+namespace libdnf {
+
+enum class TransactionItemReason : int {
+ UNKNOWN = 0,
+ DEPENDENCY = 1,
+ USER = 2,
+ CLEAN = 3, // hawkey compatibility
+ WEAK_DEPENDENCY = 4,
+ GROUP = 5
+};
+
+
+const std::string &
+TransactionItemReasonToString(TransactionItemReason reason);
+TransactionItemReason StringToTransactionItemReason(const std::string & str);
+
+
+inline bool operator<(TransactionItemReason lhs, TransactionItemReason rhs)
+{
+ if (lhs == rhs) {
+ return false;
+ }
+ TransactionItemReason order[] = {
+ TransactionItemReason::CLEAN,
+ TransactionItemReason::WEAK_DEPENDENCY,
+ TransactionItemReason::DEPENDENCY,
+ TransactionItemReason::UNKNOWN,
+ TransactionItemReason::GROUP,
+ TransactionItemReason::USER,
+ };
+ for (auto i : order) {
+ // iterate through 'order' and return according to which value matches
+ if (lhs == i) {
+ return true;
+ }
+ if (rhs == i) {
+ return false;
+ }
+ }
+ return false;
+}
+
+inline bool operator<=(TransactionItemReason lhs, TransactionItemReason rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+ return lhs < rhs;
+}
+
+
+inline bool operator>(TransactionItemReason lhs, TransactionItemReason rhs) {
+ if (lhs == rhs) {
+ return false;
+ }
+ return rhs < lhs;
+}
+
+inline bool operator>=(TransactionItemReason lhs, TransactionItemReason rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+ return lhs > rhs;
+}
+
+
+inline int
+TransactionItemReasonCompare(TransactionItemReason lhs, TransactionItemReason rhs)
+{
+ if (lhs < rhs) {
+ return -1;
+ } else if (lhs > rhs) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_TRANSACTIONITEMREASON_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <dirent.h>
+#include <fstream>
+#include <functional>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <map>
+#include <vector>
+#include <sstream>
+
+#include "../utils/bgettext/bgettext-lib.h"
+#include "../utils/filesystem.hpp"
+#include "../utils/utils.hpp"
+
+#include "RPMItem.hpp"
+#include "Swdb.hpp"
+#include "Transaction.hpp"
+#include "TransactionItem.hpp"
+#include "Transformer.hpp"
+
+namespace libdnf {
+
+static const char *sql_create_tables =
+#include "sql/create_tables.sql"
+ ;
+
+static const char * const sql_migrate_tables_1_2 =
+#include "sql/migrate_tables_1_2.sql"
+ ;
+
+void
+Transformer::createDatabase(SQLite3Ptr conn)
+{
+ conn->exec(sql_create_tables);
+ Transformer::migrateSchema(conn);
+}
+
+void
+Transformer::migrateSchema(SQLite3Ptr conn)
+{
+ // read schema version
+ SQLite3::Query query(*conn, "select value from config where key = 'version';");
+ if (query.step() == SQLite3::Statement::StepResult::ROW){
+ auto schemaVersion = query.get<std::string>("value");
+
+ if (schemaVersion == "1.1") {
+ conn->exec(sql_migrate_tables_1_2);
+ }
+ }
+ else {
+ throw Exception(_("Database Corrupted: no row 'version' in table 'config'"));
+ }
+}
+
+/**
+ * Map of supported actions (originally states): string -> enum
+ */
+static const std::map<std::string, TransactionItemAction > actions = {
+ {"Install", TransactionItemAction::INSTALL},
+ {"True-Install", TransactionItemAction::INSTALL},
+ {"Dep-Install", TransactionItemAction::INSTALL},
+ {"Downgrade", TransactionItemAction::DOWNGRADE},
+ {"Downgraded", TransactionItemAction::DOWNGRADED},
+ {"Obsoleting", TransactionItemAction::OBSOLETE},
+ {"Obsoleted", TransactionItemAction::OBSOLETED},
+ {"Update", TransactionItemAction::UPGRADE},
+ {"Updated", TransactionItemAction::UPGRADED},
+ {"Erase", TransactionItemAction::REMOVE},
+ {"Reinstall", TransactionItemAction::REINSTALL},
+ {"Reinstalled", TransactionItemAction::REINSTALL}};
+
+/**
+ * Map of supported reasons: string -> enum
+ */
+static const std::map< std::string, TransactionItemReason > reasons = {
+ {"dep", TransactionItemReason::DEPENDENCY},
+ {"user", TransactionItemReason::USER},
+ {"clean", TransactionItemReason::CLEAN},
+ {"weak", TransactionItemReason::WEAK_DEPENDENCY},
+ {"group", TransactionItemReason::GROUP}};
+
+/**
+ * Convert string reason into appropriate enumerated variant
+ */
+TransactionItemReason
+Transformer::getReason(const std::string &reason)
+{
+ auto it = reasons.find(reason);
+ if (it == reasons.end()) {
+ return TransactionItemReason::UNKNOWN;
+ }
+ return it->second;
+}
+
+/**
+ * Default constructor of the Transformer object
+ * \param outputFile path to output SQLite3 database
+ * \param inputDir directory to load data from (e.g. `/var/lib/dnf/`)
+ */
+Transformer::Transformer(const std::string &inputDir, const std::string &outputFile)
+ : inputDir(inputDir)
+ , outputFile(outputFile)
+{
+}
+
+/**
+ * Perform the database transformation routine.
+ * The database is transformed in-memory.
+ * Final scheme is dumped into outputFile
+ */
+void
+Transformer::transform()
+{
+ auto swdb = std::make_shared< SQLite3 >(":memory:");
+
+ if (pathExists(outputFile.c_str())) {
+ throw std::runtime_error("DB file already exists:" + outputFile);
+ }
+
+ // create directory path if necessary
+ makeDirPath(outputFile);
+
+ // create a new database file
+ createDatabase(swdb);
+
+ // migrate history db if it exists
+ try {
+ // make a copy of source database to make creating indexes temporary
+ auto history = std::make_shared< SQLite3 >(":memory:");
+ history->restore(historyPath().c_str());
+
+ // create additional indexes in the source database to increase conversion speed
+ history->exec("CREATE INDEX IF NOT EXISTS i_trans_cmdline_tid ON trans_cmdline(tid);");
+ history->exec("CREATE INDEX IF NOT EXISTS i_trans_data_pkgs_tid ON trans_data_pkgs(tid);");
+ history->exec("CREATE INDEX IF NOT EXISTS i_trans_script_stdout_tid ON trans_script_stdout(tid);");
+ history->exec("CREATE INDEX IF NOT EXISTS i_trans_with_pkgs_tid_pkgtupid ON trans_with_pkgs(tid, pkgtupid);");
+
+ // transform objects
+ transformTrans(swdb, history);
+
+ // transform groups
+ transformGroups(swdb);
+ }
+ catch (Exception &) {
+ // TODO: use a different (more specific) exception
+ }
+
+ // dump database to a file
+ swdb->backup(outputFile);
+}
+
+/**
+ * Transform transactions from the history database
+ * \param swdb pointer to swdb SQLite3 object
+ * \param swdb pointer to history database SQLite3 object
+ */
+void
+Transformer::transformTrans(SQLite3Ptr swdb, SQLite3Ptr history)
+{
+ std::vector< std::shared_ptr< TransformerTransaction > > result;
+
+ // we need to left join with trans_cmdline
+ // there is no cmdline for certain transactions (e.g. 1)
+ const char *trans_sql = R"**(
+ SELECT
+ tb.tid as id,
+ tb.timestamp as dt_begin,
+ tb.rpmdb_version rpmdb_version_begin,
+ tb.loginuid as user_id,
+ te.timestamp as dt_end,
+ te.rpmdb_version as rpmdb_version_end,
+ te.return_code as state,
+ tc.cmdline as cmdline
+ FROM
+ trans_beg tb
+ JOIN trans_end te using(tid)
+ LEFT JOIN trans_cmdline tc using(tid)
+ ORDER BY
+ tb.tid
+ )**";
+
+ const char *releasever_sql = R"**(
+ SELECT DISTINCT
+ trans_data_pkgs.tid as tid,
+ yumdb_val as releasever
+ FROM
+ trans_data_pkgs
+ JOIN
+ pkg_yumdb USING (pkgtupid)
+ WHERE
+ yumdb_key='releasever'
+ )**";
+
+ // get release version for all the transactions
+ std::map< int64_t, std::string > releasever;
+ SQLite3::Query releasever_query(*history.get(), releasever_sql);
+ while (releasever_query.step() == SQLite3::Statement::StepResult::ROW) {
+ std::string releaseVerStr = releasever_query.get< std::string >("releasever");
+ releasever[releasever_query.get< int64_t >("tid")] = releaseVerStr;
+ }
+
+ // iterate over history transactions
+ SQLite3::Query query(*history.get(), trans_sql);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ auto trans = std::make_shared< TransformerTransaction >(swdb);
+ trans->setId(query.get< int >("id"));
+ trans->setDtBegin(query.get< int64_t >("dt_begin"));
+ trans->setDtEnd(query.get< int64_t >("dt_end"));
+ trans->setRpmdbVersionBegin(query.get< std::string >("rpmdb_version_begin"));
+ trans->setRpmdbVersionEnd(query.get< std::string >("rpmdb_version_end"));
+
+ // set release version if available
+ auto it = releasever.find(trans->getId());
+ if (it != releasever.end()) {
+ trans->setReleasever(it->second);
+ }
+
+ trans->setUserId(query.get< int >("user_id"));
+ trans->setCmdline(query.get< std::string >("cmdline"));
+
+ TransactionState state = query.get< int >("state") == 0 ? TransactionState::DONE : TransactionState::ERROR;
+
+ transformRPMItems(swdb, history, trans);
+ transformTransWith(swdb, history, trans);
+
+ trans->begin();
+
+ transformOutput(history, trans);
+
+ trans->finish(state);
+ }
+}
+
+static void
+fillRPMItem(std::shared_ptr< RPMItem > rpm, SQLite3::Query &query)
+{
+ rpm->setName(query.get< std::string >("name"));
+ rpm->setEpoch(query.get< int64_t >("epoch"));
+ rpm->setVersion(query.get< std::string >("version"));
+ rpm->setRelease(query.get< std::string >("release"));
+ rpm->setArch(query.get< std::string >("arch"));
+ rpm->save();
+}
+
+/**
+ * Transform binding between a Transaction and packages, which performed the transaction.
+ * \param swdb pointer to swdb SQLite3 object
+ * \param swdb pointer to history database SQLite3 object
+ */
+void
+Transformer::transformTransWith(SQLite3Ptr swdb,
+ SQLite3Ptr history,
+ std::shared_ptr< TransformerTransaction > trans)
+{
+ const char *sql = R"**(
+ SELECT
+ name,
+ epoch,
+ version,
+ release,
+ arch
+ FROM
+ trans_with_pkgs
+ JOIN pkgtups using (pkgtupid)
+ WHERE
+ tid=?
+ )**";
+
+ // transform stdout
+ SQLite3::Query query(*history.get(), sql);
+ query.bindv(trans->getId());
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ // create RPM item object
+ auto rpm = std::make_shared< RPMItem >(swdb);
+ fillRPMItem(rpm, query);
+ trans->addSoftwarePerformedWith(rpm);
+ }
+}
+
+/**
+ * Transform transaction console outputs.
+ * \param swdb pointer to history database SQLite3 object
+ */
+void
+Transformer::transformOutput(SQLite3Ptr history, std::shared_ptr< TransformerTransaction > trans)
+{
+ const char *sql = R"**(
+ SELECT
+ line
+ FROM
+ trans_script_stdout
+ WHERE
+ tid = ?
+ ORDER BY
+ lid
+ )**";
+
+ // transform stdout
+ SQLite3::Query query(*history.get(), sql);
+ query.bindv(trans->getId());
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ trans->addConsoleOutputLine(1, query.get< std::string >("line"));
+ }
+
+ sql = R"**(
+ SELECT
+ msg
+ FROM
+ trans_error
+ WHERE
+ tid = ?
+ ORDER BY
+ mid
+ )**";
+
+ // transform stderr
+ SQLite3::Query errorQuery(*history.get(), sql);
+ errorQuery.bindv(trans->getId());
+ while (errorQuery.step() == SQLite3::Statement::StepResult::ROW) {
+ trans->addConsoleOutputLine(2, errorQuery.get< std::string >("msg"));
+ }
+}
+
+static void
+getYumdbData(int64_t itemId, SQLite3Ptr history, TransactionItemReason &reason, std::string &repoid)
+{
+ const char *sql = R"**(
+ SELECT
+ yumdb_key as key,
+ yumdb_val as value
+ FROM
+ pkg_yumdb
+ WHERE
+ pkgtupid=?
+ and key IN ('reason', 'from_repo')
+ )**";
+
+ // load reason and repoid data from yumdb
+ SQLite3::Query query(*history.get(), sql);
+ query.bindv(itemId);
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+ std::string key = query.get< std::string >("key");
+ if (key == "reason") {
+ reason = Transformer::getReason(query.get< std::string >("value"));
+ } else if (key == "from_repo") {
+ repoid = query.get< std::string >("value");
+ }
+ }
+}
+
+/**
+ * Transform RPM Items from a particular transaction.
+ * \param swdb pointer to swdb SQLite3 object
+ * \param swdb pointer to history database SQLite3 objects
+ * \param trans Transaction whose items should be transformed
+ */
+void
+Transformer::transformRPMItems(SQLite3Ptr swdb,
+ SQLite3Ptr history,
+ std::shared_ptr< TransformerTransaction > trans)
+{
+ // the order is important here - its Update, Updated
+ const char *pkg_sql = R"**(
+ SELECT
+ t.state,
+ t.done,
+ r.pkgtupid as id,
+ r.name,
+ r.epoch,
+ r.version,
+ r.release,
+ r.arch
+ FROM
+ trans_data_pkgs t
+ JOIN pkgtups r using(pkgtupid)
+ WHERE
+ t.tid=?
+ )**";
+
+ SQLite3::Query query(*history.get(), pkg_sql);
+ query.bindv(trans->getId());
+
+ TransactionItemPtr last = nullptr;
+
+ /*
+ * Item in a single transaction can be both Obsoleted multiple times and Updated.
+ * We need to keep track of all the obsoleted items,
+ * so we can promote them to Updated in case.
+ * Obsoleted records will be kept in item_replaced table,
+ * so it's always obvious, that particular package was both Obsoleted
+ * and Updated. Technically, we could replace action Obsoleted with action Erase.
+ */
+ std::map< int64_t, TransactionItemPtr > obsoletedItems;
+
+ // iterate over transaction packages in the history database
+ while (query.step() == SQLite3::Statement::StepResult::ROW) {
+
+ // create RPM item object
+ auto rpm = std::make_shared< RPMItem >(swdb);
+ fillRPMItem(rpm, query);
+
+ // get item state/action
+ std::string stateString = query.get< std::string >("state");
+ TransactionItemAction action = actions.at(stateString);
+
+ // `Obsoleting` record is duplicated with previous record (with different action)
+ if (action == TransactionItemAction::OBSOLETE) {
+ continue;
+ }
+
+ // find out if an item was previously obsoleted
+ auto pastObsoleted = obsoletedItems.find(rpm->getId());
+
+ TransactionItemPtr transItem = nullptr;
+
+ if (pastObsoleted == obsoletedItems.end()) {
+ // item hasn't been obsoleted yet
+
+ // load reason and from_repo
+ TransactionItemReason reason = TransactionItemReason::UNKNOWN;
+ std::string repoid;
+ getYumdbData(query.get< int64_t >("id"), history, reason, repoid);
+
+ // add TransactionItem object
+ transItem = trans->addItem(rpm, repoid, action, reason);
+ transItem->setState(query.get< std::string >("done") == "TRUE" ? TransactionItemState::DONE : TransactionItemState::ERROR);
+ } else {
+ // item has been obsoleted - we just need to update the action
+ transItem = pastObsoleted->second;
+ transItem->setAction(action);
+ }
+
+ // resolve replaced by
+ switch (action) {
+ case TransactionItemAction::OBSOLETED:
+ obsoletedItems[rpm->getId()] = transItem;
+ transItem->addReplacedBy(last);
+ break;
+ case TransactionItemAction::DOWNGRADED:
+ case TransactionItemAction::UPGRADED:
+ transItem->addReplacedBy(last);
+ break;
+ default:
+ break;
+ }
+
+ // keep the last item in case of obsoletes
+ last = transItem;
+ }
+}
+
+/**
+ * Construct CompsGroupItem object from JSON
+ * \param group group json object
+ */
+CompsGroupItemPtr
+Transformer::processGroup(SQLite3Ptr swdb, const char *groupId, struct json_object *group)
+{
+ struct json_object *value;
+
+ // create group
+ auto compsGroup = std::make_shared< CompsGroupItem >(swdb);
+
+ compsGroup->setGroupId(groupId);
+
+ if (json_object_object_get_ex(group, "name", &value)) {
+ compsGroup->setName(json_object_get_string(value));
+ }
+
+ if (json_object_object_get_ex(group, "ui_name", &value)) {
+ compsGroup->setTranslatedName(json_object_get_string(value));
+ }
+
+ // TODO parse pkg_types to CompsPackageType
+ if (json_object_object_get_ex(group, "full_list", &value)) {
+ int len = json_object_array_length(value);
+ for (int i = 0; i < len; ++i) {
+ const char *key = json_object_get_string(json_object_array_get_idx(value, i));
+ compsGroup->addPackage(key, true, CompsPackageType::MANDATORY);
+ }
+ }
+
+ // TODO parse pkg_types to CompsPackageType
+ if (json_object_object_get_ex(group, "pkg_exclude", &value)) {
+ int len = json_object_array_length(value);
+ for (int i = 0; i < len; ++i) {
+ const char *key = json_object_get_string(json_object_array_get_idx(value, i));
+ compsGroup->addPackage(key, false, CompsPackageType::MANDATORY);
+ }
+ }
+
+ compsGroup->save();
+ return compsGroup;
+}
+
+/**
+ * Construct CompsEnvironmentItem object from JSON
+ * \param env environment json object
+ */
+std::shared_ptr< CompsEnvironmentItem >
+Transformer::processEnvironment(SQLite3Ptr swdb, const char *envId, struct json_object *env)
+{
+ struct json_object *value;
+
+ // create environment
+ auto compsEnv = std::make_shared< CompsEnvironmentItem >(swdb);
+ compsEnv->setEnvironmentId(envId);
+
+ if (json_object_object_get_ex (env, "name", &value)) {
+ compsEnv->setName(json_object_get_string(value));
+ }
+
+ if (json_object_object_get_ex (env, "ui_name", &value)) {
+ compsEnv->setTranslatedName(json_object_get_string(value));
+ }
+
+ // TODO parse pkg_types/grp_types to CompsPackageType
+ if (json_object_object_get_ex(env, "full_list", &value)) {
+ int len = json_object_array_length(value);
+ for (int i = 0; i < len; ++i) {
+ const char *key = json_object_get_string(json_object_array_get_idx(value, i));
+ compsEnv->addGroup(key, true, CompsPackageType::MANDATORY);
+ }
+ }
+
+ // TODO parse pkg_types/grp_types to CompsPackageType
+ if (json_object_object_get_ex(env, "pkg_exclude", &value)) {
+ int len = json_object_array_length(value);
+ for (int i = 0; i < len; ++i) {
+ const char *key = json_object_get_string(json_object_array_get_idx(value, i));
+ compsEnv->addGroup(key, false, CompsPackageType::MANDATORY);
+ }
+ }
+
+ compsEnv->save();
+
+ return compsEnv;
+}
+
+/**
+ * Create fake transaction for groups in persistor
+ * \param swdb pointer to swdb SQLite3 object
+ * \param root group persistor root node
+ */
+void
+Transformer::processGroupPersistor(SQLite3Ptr swdb, struct json_object *root)
+{
+ // there is no rpmdb change in this transaction,
+ // use rpmdb version from the last converted transaction
+ Swdb swdbObj(swdb, false);
+ auto lastTrans = swdbObj.getLastTransaction();
+
+ auto trans = swdb_private::Transaction(swdb);
+
+ // load sequences
+ struct json_object *groups;
+ struct json_object *envs;
+
+ // add groups
+ if (json_object_object_get_ex(root, "GROUPS", &groups)) {
+ json_object_object_foreach(groups, key, val) {
+ trans.addItem(processGroup (swdb, key, val),
+ {}, // repoid
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER);
+ }
+ }
+
+ // add environments
+ if (json_object_object_get_ex(root, "ENVIRONMENTS", &envs)) {
+ json_object_object_foreach(envs, key, val) {
+ trans.addItem(processEnvironment (swdb, key, val),
+ {}, // repoid
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER);
+ }
+ }
+
+ trans.begin();
+
+ auto now = time(NULL);
+ trans.setDtBegin(now);
+ trans.setDtEnd(now);
+
+ if (lastTrans) {
+ trans.setRpmdbVersionBegin(lastTrans->getRpmdbVersionEnd());
+ trans.setRpmdbVersionEnd(trans.getRpmdbVersionBegin());
+ } else {
+ // no transaction found -> use 0 packages + hash for an empty string
+ trans.setRpmdbVersionBegin("0:da39a3ee5e6b4b0d3255bfef95601890afd80709");
+ trans.setRpmdbVersionEnd(trans.getRpmdbVersionBegin());
+ }
+
+ for (auto i : trans.getItems()) {
+ i->setState(TransactionItemState::DONE);
+ i->save();
+ }
+
+ trans.finish(TransactionState::DONE);
+}
+
+/**
+ * Load group persistor into JSON object and perform transformation
+ * \param swdb pointer to swdb SQLite3 object
+ */
+void
+Transformer::transformGroups(SQLite3Ptr swdb)
+{
+ std::string groupsFile(inputDir);
+
+ // create the groups.json path
+ if (groupsFile.back() != '/') {
+ groupsFile += '/';
+ }
+ groupsFile += "groups.json";
+
+ std::ifstream groupsStream(groupsFile);
+
+ if (!groupsStream.is_open()) {
+ return;
+ }
+
+ std::stringstream buffer;
+ buffer << groupsStream.rdbuf();
+
+ struct json_object *root = json_tokener_parse(buffer.str().c_str());
+
+ processGroupPersistor(swdb, root);
+}
+
+/**
+ * Try to find the history database in the inputDir
+ * \return path to the latest history database in the inputDir
+ */
+std::string
+Transformer::historyPath()
+{
+ std::string historyDir(inputDir);
+
+ // construct the history directory path
+ if (historyDir.back() != '/') {
+ historyDir += '/';
+ }
+ historyDir += "history";
+
+ // vector for possible history DB files
+ std::vector< std::string > possibleFiles;
+
+ // open history directory
+ struct dirent *dp;
+ std::unique_ptr<DIR, std::function<void(DIR *)>> dirp(opendir(historyDir.c_str()), [](DIR* ptr){
+ closedir(ptr);
+ });
+
+ if (!dirp) {
+ throw Exception(_("Transformer: can't open history persist dir"));
+ }
+
+ // iterate over history directory and look for 'history-*.sqlite' files
+ while ((dp = readdir(dirp.get())) != nullptr) {
+ std::string fileName(dp->d_name);
+ if (libdnf::string::startsWith(fileName, "history-") &&
+ libdnf::string::endsWith(fileName, ".sqlite")) {
+ possibleFiles.push_back(fileName);
+ }
+ }
+
+ if (possibleFiles.empty()) {
+ throw Exception(_("Couldn't find a history database"));
+ }
+
+ // find the latest DB file
+ std::sort(possibleFiles.begin(), possibleFiles.end());
+
+ // return the path
+ return historyDir + "/" + possibleFiles.back();
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSFORMER_HPP
+#define LIBDNF_TRANSACTION_TRANSFORMER_HPP
+
+#include <json.h>
+#include <memory>
+#include <vector>
+
+#include "../utils/sqlite3/Sqlite3.hpp"
+
+#include "CompsEnvironmentItem.hpp"
+#include "CompsGroupItem.hpp"
+#include "RPMItem.hpp"
+#include "private/Transaction.hpp"
+#include "private/TransformerTransaction.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+/**
+ * Class providing an interface to the database transformation
+ */
+class Transformer {
+public:
+ class Exception : public std::runtime_error {
+ public:
+ Exception(const std::string &msg)
+ : runtime_error(msg)
+ {
+ }
+ Exception(const char *msg)
+ : runtime_error(msg)
+ {
+ }
+ };
+
+ Transformer(const std::string &inputDir, const std::string &outputFile);
+ void transform();
+
+ static void createDatabase(SQLite3Ptr conn);
+ static void migrateSchema(SQLite3Ptr conn);
+
+ static TransactionItemReason getReason(const std::string &reason);
+ static const char *getVersion() noexcept { return "1.2"; }
+
+protected:
+ void transformTrans(SQLite3Ptr swdb, SQLite3Ptr history);
+
+ void transformGroups(SQLite3Ptr swdb);
+ void processGroupPersistor(SQLite3Ptr swdb, struct json_object *root);
+
+private:
+ void transformRPMItems(SQLite3Ptr swdb,
+ SQLite3Ptr history,
+ std::shared_ptr< TransformerTransaction > trans);
+ void transformOutput(SQLite3Ptr history, std::shared_ptr< TransformerTransaction > trans);
+ void transformTransWith(SQLite3Ptr swdb,
+ SQLite3Ptr history,
+ std::shared_ptr< TransformerTransaction > trans);
+ CompsGroupItemPtr processGroup(SQLite3Ptr swdb,
+ const char *groupId,
+ struct json_object *group);
+ std::shared_ptr<CompsEnvironmentItem> processEnvironment(SQLite3Ptr swdb,
+ const char *envId,
+ struct json_object *env);
+ std::string historyPath();
+ const std::string inputDir;
+ const std::string outputFile;
+ const std::string transformFile;
+};
+
+} // namespace libdnf
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TYPES_HPP
+#define LIBDNF_TRANSACTION_TYPES_HPP
+
+#include "TransactionItemReason.hpp"
+
+namespace libdnf {
+
+enum class TransactionState : int {
+ UNKNOWN = 0,
+ DONE = 1,
+ ERROR = 2
+};
+
+enum class TransactionItemState : int {
+ UNKNOWN = 0, // default state, must be changed before save
+ DONE = 1,
+ ERROR = 2
+};
+
+enum class ItemType : int { UNKNOWN = 0, RPM = 1, GROUP = 2, ENVIRONMENT = 3 };
+
+// Any time you add a new action, change functions that resolve reasons,
+// because removed items (RPMs) must be excluded from reason resolution:
+// * RPMItem.cpp - RPMItem::resolveTransactionItemReason
+enum class TransactionItemAction : int {
+ INSTALL = 1, // a new package that was installed on the system
+ DOWNGRADE = 2, // an older package version that replaced previously installed version
+ DOWNGRADED = 3, // an original package version that was replaced
+ OBSOLETE = 4, //
+ OBSOLETED = 5, //
+ UPGRADE = 6, //
+ UPGRADED = 7, //
+ REMOVE = 8, // a package that was removed from the system
+ REINSTALL = 9, // a package that was reinstalled with the identical version
+ REINSTALLED = 10, // a package that was reinstalled with the identical version (old repo, for example)
+ REASON_CHANGE = 11 // a package was kept on the system but it's reason has changed
+};
+
+} // namespace libdnf
+/*
+Install
+-------
+* Command example: dnf install bash
+* Old package(s): (none)
+* New package(s): bash-4.4.12-5
+* -> new TransactionItem: item="bash-4.4.12-5", action=INSTALL, reason=<new>, replaced_by=NULL
+
+Downgrade
+---------
+* Command example: dnf downgrade bash
+* Old package(s): bash-4.4.12-5
+* New package(s): bash-4.4.12-4
+* -> new TransactionItem: item="bash-4.4.12-5", action=DOWNGRADE, reason=<inherited>,
+replaced_by=NULL
+* -> new TransactionItem: item="bash-4.4.12-4", action=DOWNGRADED, reason=<inherited>,
+replaced_by=<id of bash-4.4.12-5 transaction item>
+
+Obsolete
+--------
+* Command example: dnf upgrade
+* Old package(s): sysvinit-2.88-9
+* New package(s): systemd-233-6
+* -> new TransactionItem: item="systemd-233-6", action=OBSOLETE, reason=<inherited>,
+replaced_by=NULL
+* -> new TransactionItem: item="sysvinit-2.88-9", action=OBSOLETED, reason=<inherited>,
+replaced_by=<id of systemd-233-6 transaction item>
+
+Obsolete & Upgrade
+------------------
+* Command example: dnf upgrade
+* Old package(s): systemd-233-5, sysvinit-2.88-9
+* New package(s): systemd-233-6 (introducing Obsoletes: sysvinit)
+* -> new TransactionItem: item="systemd-233-6", action=UPGRADE, reason=<inherited>, replaced_by=NULL
+* -> new TransactionItem: item="systemd-233-5", action=UPGRADED, reason=<inherited>, replaced_by=<id
+of systemd-233-6 transaction item>
+* -> new TransactionItem: item="sysvinit-2.88-9", action=OBSOLETED, reason=<inherited>,
+replaced_by=<id of systemd-233-6 transaction item>
+
+Upgrade
+-------
+* Command example: dnf upgrade
+* Old package(s): bash-4.4.12-4
+* New package(s): bash-4.4.12-5
+* -> new TransactionItem: item="bash-4.4.12-5", action=UPGRADE, reason=<inherited>, replaced_by=NULL
+* -> new TransactionItem: item="bash-4.4.12-4", action=UPGRADED, reason=<inherited>, replaced_by=<id
+of bash-4.4.12-4 transaction item>
+
+Remove
+------
+* Command example: dnf remove bash
+* Old package(s): bash-4.4.12-5
+* New package(s): (none)
+* -> new TransactionItem: item="bash-4.4.12-5", action=REMOVED, reason=<new>, replaced_by=NULL
+
+Reinstall
+---------
+* Command example: dnf reinstall bash
+* Old package(s): bash-4.4.12-5
+* New package(s): bash-4.4.12-5
+* -> new TransactionItem: item="bash-4.4.12-5", action=REINSTALL, reason=<inherited>,
+replaced_by=NULL
+
+Reason Change
+-------------
+* Command example: dnf mark install bash
+* Old package(s): bash-4.4.12-5
+* New package(s): bash-4.4.12-5
+* -> new TransactionItem: item="bash-4.4.12-5", action=REASON_CHANGE, reason=<new>,
+
+Reasons:
+* new = a brand new reason why a package was installed or removed
+* inherited = a package was installed in the past, re-use it's reason in existing transaction
+*/
+
+#endif // LIBDNF_TRANSACTION_TYPES_HPP
--- /dev/null
+set(TRANSACTION_SRCS
+ ${TRANSACTION_SRCS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Repo.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Transaction.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Repo.hpp"
+
+namespace libdnf {
+namespace swdb_private {
+
+// initialize static variable Repo::cache
+std::map< std::string, RepoPtr > Repo::cache;
+
+Repo::Repo(SQLite3Ptr conn)
+ : conn{conn}
+{
+}
+
+void
+Repo::save()
+{
+ dbSelectOrInsert();
+}
+
+void
+Repo::dbInsert()
+{
+ const char *sql =
+ "INSERT INTO "
+ " repo "
+ "VALUES "
+ " (null, ?)";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getRepoId());
+ query.step();
+ setId(conn->lastInsertRowID());
+}
+
+std::shared_ptr< Repo >
+Repo::getCached(SQLite3Ptr conn, const std::string &repoid)
+{
+ // HACK: this is kind of ugly - key is generated from repoid and sqlite3 pointer
+ auto key = repoid + "/" + std::to_string(reinterpret_cast< std::size_t >(conn.get()));
+ auto it = cache.find(key);
+ if (it == cache.end()) {
+ // cache miss
+ auto repo = std::make_shared< Repo >(conn);
+ repo->setRepoId(repoid);
+ repo->save();
+ cache[key] = repo;
+ return repo;
+ } else {
+ // cache hit
+ return it->second;
+ }
+}
+
+void
+Repo::dbSelectOrInsert()
+{
+ const char *sql =
+ "SELECT "
+ " id "
+ "FROM "
+ " repo "
+ "WHERE "
+ " repoid = ? ";
+
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getRepoId());
+ SQLite3::Statement::StepResult result = query.step();
+
+ if (result == SQLite3::Statement::StepResult::ROW) {
+ setId(query.get< int >(0));
+ } else {
+ // insert and get the ID back
+ dbInsert();
+ }
+}
+
+} // namespace swdb_private
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_REPO_HPP
+#define LIBDNF_TRANSACTION_REPO_HPP
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "../../utils/sqlite3/Sqlite3.hpp"
+
+namespace libdnf {
+namespace swdb_private {
+
+class Repo;
+typedef std::shared_ptr< Repo > RepoPtr;
+
+class Repo {
+public:
+ static RepoPtr getCached(SQLite3Ptr conn, const std::string &repoid);
+ static std::map< std::string, RepoPtr > cache;
+
+ Repo(SQLite3Ptr conn);
+
+ int64_t getId() const noexcept { return id; }
+ void setId(int64_t value) { id = value; }
+
+ const std::string &getRepoId() const noexcept { return repoId; }
+ void setRepoId(const std::string &value) { repoId = value; }
+
+ void save();
+
+protected:
+ void dbInsert();
+ void dbSelectOrInsert();
+
+ int64_t id = 0;
+ std::string repoId;
+ SQLite3Ptr conn;
+};
+
+} // namespace swdb_private
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_REPO_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "../../utils/bgettext/bgettext-lib.h"
+#include "../../utils/tinyformat/tinyformat.hpp"
+
+#include "CompsEnvironmentItem.hpp"
+#include "CompsGroupItem.hpp"
+#include "RPMItem.hpp"
+#include "Transaction.hpp"
+#include "TransactionItem.hpp"
+
+namespace libdnf {
+
+swdb_private::Transaction::Transaction(SQLite3Ptr conn)
+ : libdnf::Transaction(conn)
+{
+}
+
+void
+swdb_private::Transaction::begin()
+{
+ if (id != 0) {
+ throw std::runtime_error(_("Transaction has already began!"));
+ }
+ dbInsert();
+ saveItems();
+}
+
+void
+swdb_private::Transaction::finish(TransactionState state)
+{
+ // save states to the database before checking for UNKNOWN state
+ for (auto i : getItems()) {
+ i->saveState();
+ }
+
+ for (auto i : getItems()) {
+ if (i->getState() == TransactionItemState::UNKNOWN) {
+ throw std::runtime_error(
+ tfm::format(_("TransactionItem state is not set: %s"), i->getItem()->toStr()));
+ }
+ }
+
+ setState(state);
+ dbUpdate();
+}
+
+void
+swdb_private::Transaction::dbInsert()
+{
+ const char *sql =
+ "INSERT INTO "
+ " trans ("
+ " dt_begin, "
+ " dt_end, "
+ " rpmdb_version_begin, "
+ " rpmdb_version_end, "
+ " releasever, "
+ " user_id, "
+ " cmdline, "
+ " state, "
+ " comment, "
+ " id "
+ " ) "
+ "VALUES "
+ " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getDtBegin(),
+ getDtEnd(),
+ getRpmdbVersionBegin(),
+ getRpmdbVersionEnd(),
+ getReleasever(),
+ getUserId(),
+ getCmdline(),
+ static_cast< int >(getState()),
+ getComment());
+ if (getId() > 0) {
+ query.bind(9, getId());
+ }
+ query.step();
+ setId(conn->lastInsertRowID());
+
+ // add used software - has to be added at initialization state
+ if (!softwarePerformedWith.empty()) {
+ sql = R"**(
+ INSERT OR REPLACE INTO
+ trans_with (
+ trans_id,
+ item_id
+ )
+ VALUES
+ (?, ?)
+ )**";
+ SQLite3::Statement swQuery(*conn.get(), sql);
+ bool first = true;
+ for (auto software : softwarePerformedWith) {
+ if (!first) {
+ swQuery.reset();
+ }
+ first = false;
+ // save the item to create a database id
+ software->save();
+ swQuery.bindv(getId(), software->getId());
+ swQuery.step();
+ }
+ }
+}
+
+void
+swdb_private::Transaction::dbUpdate()
+{
+ const char *sql =
+ "UPDATE "
+ " trans "
+ "SET "
+ " dt_begin=?, "
+ " dt_end=?, "
+ " rpmdb_version_begin=?, "
+ " rpmdb_version_end=?, "
+ " releasever=?, "
+ " user_id=?, "
+ " cmdline=?, "
+ " state=?, "
+ " comment=? "
+ "WHERE "
+ " id = ?";
+ SQLite3::Statement query(*conn.get(), sql);
+ query.bindv(getDtBegin(),
+ getDtEnd(),
+ getRpmdbVersionBegin(),
+ getRpmdbVersionEnd(),
+ getReleasever(),
+ getUserId(),
+ getCmdline(),
+ static_cast< int >(getState()),
+ getComment(),
+ getId());
+ query.step();
+}
+
+TransactionItemPtr
+swdb_private::Transaction::addItem(std::shared_ptr< Item > item,
+ const std::string &repoid,
+ TransactionItemAction action,
+ TransactionItemReason reason)
+{
+ for (auto & i : items) {
+ if (i->getItem()->toStr() != item->toStr()) {
+ continue;
+ }
+ if (i->getRepoid() != repoid) {
+ continue;
+ }
+ if (i->getAction() != action) {
+ continue;
+ }
+ if (reason > i->getReason()) {
+ // use the more significant reason
+ i->setReason(reason);
+ }
+ // don't add duplicates to the list
+ // return an existing transaction item if exists
+ return i;
+ }
+ auto trans_item = std::make_shared< TransactionItem >(this);
+ trans_item->setItem(item);
+ trans_item->setRepoid(repoid);
+ trans_item->setAction(action);
+ trans_item->setReason(reason);
+ items.push_back(trans_item);
+ return trans_item;
+}
+
+void
+swdb_private::Transaction::saveItems()
+{
+ // TODO: remove all existing items from the database first?
+ for (auto i : items) {
+ i->save();
+ }
+
+ /* this has to be done in a separate loop to make sure
+ * that all the items already have ID assigned
+ */
+ for (auto i : items) {
+ i->saveReplacedBy();
+ }
+}
+
+/**
+ * Loader for the transaction items.
+ * \return list of transaction items associated with the transaction
+ */
+std::vector< TransactionItemPtr >
+swdb_private::Transaction::getItems()
+{
+ if (items.empty()) {
+ items = libdnf::Transaction::getItems();
+ }
+ return items;
+}
+
+/**
+ * Append software to softwarePerformedWith list.
+ * Software is saved to the database using save method and therefore
+ * all the software has to be added before transaction is saved.
+ * \param software RPMItem used to perform the transaction
+ */
+void
+swdb_private::Transaction::addSoftwarePerformedWith(std::shared_ptr< RPMItem > software)
+{
+ softwarePerformedWith.insert(software);
+}
+
+/**
+ * Save console output line for current transaction to the database. Transaction has
+ * to be saved in advance, otherwise an exception will be thrown.
+ * \param fileDescriptor UNIX file descriptor index (1 = stdout, 2 = stderr).
+ * \param line console output content
+ */
+void
+swdb_private::Transaction::addConsoleOutputLine(int fileDescriptor, const std::string &line)
+{
+ if (!getId()) {
+ throw std::runtime_error(_("Can't add console output to unsaved transaction"));
+ }
+
+ const char *sql = R"**(
+ INSERT INTO
+ console_output (
+ trans_id,
+ file_descriptor,
+ line
+ )
+ VALUES
+ (?, ?, ?);
+ )**";
+ SQLite3::Statement query(*conn, sql);
+ query.bindv(getId(), fileDescriptor, line);
+ query.step();
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSACTION_PRIVATE_HPP
+#define LIBDNF_TRANSACTION_TRANSACTION_PRIVATE_HPP
+
+#include "../Transaction.hpp"
+
+namespace libdnf {
+namespace swdb_private {
+
+class Transaction;
+typedef std::shared_ptr< Transaction > TransactionPtr;
+
+class Transaction : public libdnf::Transaction {
+public:
+ // create an empty object, don't read from db
+ explicit Transaction(SQLite3Ptr conn);
+
+ void setId(int64_t value) { id = value; }
+ void setDtBegin(int64_t value) { dtBegin = value; }
+ void setDtEnd(int64_t value) { dtEnd = value; }
+ void setRpmdbVersionBegin(const std::string &value) { rpmdbVersionBegin = value; }
+ void setRpmdbVersionEnd(const std::string &value) { rpmdbVersionEnd = value; }
+ void setReleasever(const std::string &value) { releasever = value; }
+ void setUserId(uint32_t value) { userId = value; }
+ void setCmdline(const std::string &value) { cmdline = value; }
+ void setState(TransactionState value) { state = value; }
+ void setComment(const std::string &value) { comment = value; }
+
+ std::vector< TransactionItemPtr > getItems() override;
+
+ void begin();
+ void finish(TransactionState state);
+ TransactionItemPtr addItem(std::shared_ptr< Item > item,
+ const std::string &repoid,
+ TransactionItemAction action,
+ TransactionItemReason reason);
+
+ void addConsoleOutputLine(int fileDescriptor, const std::string &line);
+ void addSoftwarePerformedWith(std::shared_ptr< RPMItem > software);
+
+protected:
+ void saveItems();
+ std::vector< TransactionItemPtr > items;
+
+ void dbInsert();
+ void dbUpdate();
+};
+
+}
+}
+
+#endif // LIBDNF_TRANSACTION_TRANSACTION_PRIVATE_HPP
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TRANSACTION_TRANSFORMERTRANSACTION_HPP
+#define LIBDNF_TRANSACTION_TRANSFORMERTRANSACTION_HPP
+
+#include "Transaction.hpp"
+
+namespace libdnf {
+
+/**
+ * Class overrides default behavior with
+ * inserting rows with explicitly set IDs
+ */
+class TransformerTransaction : public swdb_private::Transaction {
+public:
+ using swdb_private::Transaction::Transaction;
+ void begin()
+ {
+ dbInsert();
+ saveItems();
+ }
+};
+
+} // namespace libdnf
+
+#endif // LIBDNF_TRANSACTION_TRANSFORMERTRANSACTION_HPP
--- /dev/null
+# SQLite tables
+### Init
+Init file of database tables is defined in `create_tables.sql`
+
+### Migration
+Migration files should always be created following the version number in `config` table `version` col
+
+Name should be according to table version:
+if version is 1.2 name should be `migrate_tables_1_2.sql`
--- /dev/null
+R"**(
+ CREATE TABLE trans (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ dt_begin INTEGER NOT NULL, /* (unix timestamp) date and time of transaction begin */
+ dt_end INTEGER, /* (unix timestamp) date and time of transaction end */
+ rpmdb_version_begin TEXT,
+ rpmdb_version_end TEXT,
+ releasever TEXT NOT NULL, /* var: $releasever */
+ user_id INTEGER NOT NULL, /* user ID (UID) */
+ cmdline TEXT, /* recorded command line (program, options, arguments) */
+ state INTEGER NOT NULL /* (enum) */
+ );
+ CREATE TABLE repo (
+ id INTEGER PRIMARY KEY,
+ repoid TEXT NOT NULL /* repository ID aka 'repoid' */
+ );
+ CREATE TABLE console_output (
+ id INTEGER PRIMARY KEY,
+ trans_id INTEGER REFERENCES trans(id),
+ file_descriptor INTEGER NOT NULL, /* stdout: 1, stderr : 2 */
+ line TEXT NOT NULL
+ );
+ CREATE TABLE item (
+ id INTEGER PRIMARY KEY,
+ item_type INTEGER NOT NULL /* (enum) 1: rpm, 2: group, 3: env ...*/
+ );
+ CREATE TABLE trans_item (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ trans_id INTEGER REFERENCES trans(id),
+ item_id INTEGER REFERENCES item(id),
+ repo_id INTEGER REFERENCES repo(id),
+ action INTEGER NOT NULL, /* (enum) */
+ reason INTEGER NOT NULL, /* (enum) */
+ state INTEGER NOT NULL /* (enum) */
+ );
+ CREATE TABLE item_replaced_by ( /* M:N relationship between transaction items */
+ trans_item_id INTEGER REFERENCES trans_item(id),
+ by_trans_item_id INTEGER REFERENCES trans_item(id),
+ PRIMARY KEY (trans_item_id, by_trans_item_id)
+ );
+ CREATE TABLE trans_with (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ trans_id INTEGER REFERENCES trans(id),
+ item_id INTEGER REFERENCES item(id),
+ CONSTRAINT trans_with_unique_trans_item UNIQUE (trans_id, item_id)
+ );
+
+ /* item: rpm */
+ CREATE TABLE rpm (
+ item_id INTEGER UNIQUE NOT NULL,
+ name TEXT NOT NULL,
+ epoch INTEGER NOT NULL, /* empty epoch is stored as 0 */
+ version TEXT NOT NULL,
+ release TEXT NOT NULL,
+ arch TEXT NOT NULL,
+ FOREIGN KEY(item_id) REFERENCES item(id),
+ CONSTRAINT rpm_unique_nevra UNIQUE (name, epoch, version, release, arch)
+ );
+
+ /* item: comps-group */
+ CREATE TABLE comps_group (
+ item_id INTEGER UNIQUE NOT NULL,
+ groupid TEXT NOT NULL,
+ name TEXT NOT NULL,
+ translated_name TEXT NOT NULL,
+ pkg_types INTEGER NOT NULL,
+ FOREIGN KEY(item_id) REFERENCES item(id)
+ );
+ CREATE TABLE comps_group_package (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ group_id INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ installed INTEGER NOT NULL,
+ pkg_type INTEGER NOT NULL,
+ FOREIGN KEY(group_id) REFERENCES comps_group(item_id),
+ CONSTRAINT comps_group_package_unique_name UNIQUE (group_id, name)
+ );
+
+ /* item: comps-environment */
+ CREATE TABLE comps_environment (
+ item_id INTEGER UNIQUE NOT NULL,
+ environmentid TEXT NOT NULL,
+ name TEXT NOT NULL,
+ translated_name TEXT NOT NULL,
+ pkg_types INTEGER NOT NULL,
+ FOREIGN KEY(item_id) REFERENCES item(id)
+ );
+ CREATE TABLE comps_environment_group (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ environment_id INTEGER NOT NULL,
+ groupid TEXT NOT NULL,
+ installed INTEGER NOT NULL,
+ group_type INTEGER NOT NULL,
+ FOREIGN KEY(environment_id) REFERENCES comps_environment(item_id),
+ CONSTRAINT comps_environment_group_unique_groupid UNIQUE (environment_id, groupid)
+ );
+
+ CREATE INDEX rpm_name ON rpm(name);
+ CREATE INDEX trans_item_trans_id ON trans_item(trans_id);
+ CREATE INDEX trans_item_item_id ON trans_item(item_id);
+
+ CREATE TABLE config (
+ key TEXT PRIMARY KEY,
+ value TEXT NOT NULL
+ );
+ INSERT INTO config VALUES (
+ 'version',
+ '1.1'
+ );
+)**"
--- /dev/null
+R"**(
+BEGIN TRANSACTION;
+ ALTER TABLE trans
+ ADD comment TEXT DEFAULT '';
+ UPDATE config
+ SET value = '1.2'
+ WHERE key = 'version';
+COMMIT;
+)**"
--- /dev/null
+add_subdirectory(bgettext)
+add_subdirectory(iniparser)
+add_subdirectory(regex)
+add_subdirectory(sqlite3)
+add_subdirectory(smartcols)
+
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/filesystem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/url-encode.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/File.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompressedFile.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/GLibLogger.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/os-release.cpp
+ PARENT_SCOPE
+)
+
+set(UTILS_PUBLIC_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/logger.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/PreserveOrderMap.hpp
+)
+
+install(FILES ${UTILS_PUBLIC_HEADERS} DESTINATION include/libdnf/utils)
--- /dev/null
+#include "CompressedFile.hpp"
+#include <utility>
+#include <sstream>
+
+extern "C" {
+# include <solv/solv_xfopen.h>
+};
+
+#include <cerrno>
+#include <system_error>
+
+namespace libdnf {
+
+CompressedFile::CompressedFile(const std::string &filePath)
+: File(filePath) {}
+
+CompressedFile::~CompressedFile() = default;
+
+void CompressedFile::open(const char *mode)
+{
+ // There are situations when solv_xfopen returns NULL but it does not set errno.
+ // In this case errno value is random, so we set a default value.
+ errno = 0;
+ file = solv_xfopen(filePath.c_str(), mode);
+ if (!file) {
+ if (errno) {
+ throw OpenError(filePath, std::system_category().message(errno));
+ }
+ throw OpenError(filePath);
+ }
+}
+
+std::string CompressedFile::getContent()
+{
+ if (!file) {
+ throw NotOpenedException(filePath);
+ }
+
+ constexpr size_t bufferSize = 4096;
+ char buffer[bufferSize];
+ std::ostringstream ss;
+ size_t bytesRead;
+
+ do {
+ try {
+ bytesRead = read(buffer, bufferSize);
+ } catch (const ReadError & e) {
+ throw ReadError(std::string(e.what()) + " Likely the archive is damaged.");
+ }
+ ss.write(buffer, bytesRead);
+ } while (bytesRead == bufferSize);
+
+ return ss.str();
+}
+
+}
--- /dev/null
+#ifndef LIBDNF_GZFILE_HPP
+#define LIBDNF_GZFILE_HPP
+
+#include "File.hpp"
+
+namespace libdnf {
+
+class CompressedFile : public File
+{
+public:
+ explicit CompressedFile(const std::string &filePath);
+ ~CompressedFile() override;
+
+ void open(const char *mode) override;
+
+ std::string getContent() override;
+};
+
+}
+
+
+#endif //LIBDNF_GZFILE_HPP
--- /dev/null
+#include "File.hpp"
+#include "CompressedFile.hpp"
+#include "utils.hpp"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sstream>
+#include <utility>
+#include <iostream>
+
+#include <cerrno>
+#include <system_error>
+
+extern "C" {
+# include <solv/solv_xfopen.h>
+};
+
+namespace libdnf {
+
+std::unique_ptr<File> File::newFile(const std::string &filePath)
+{
+ if (solv_xfopen_iscompressed(filePath.c_str()) == 1) {
+ return std::unique_ptr<CompressedFile>(new CompressedFile(filePath));
+ } else {
+ return std::unique_ptr<File>(new File(filePath));
+ }
+}
+
+File::File(const std::string &filePath)
+ : filePath(filePath)
+ , file(nullptr)
+{}
+
+File::~File()
+{
+ try {
+ close();
+ } catch (IOError &) {}
+}
+
+void File::open(const char *mode)
+{
+ file = fopen(filePath.c_str(), mode);
+ if (!file) {
+ throw OpenError(filePath, std::system_category().message(errno));
+ }
+}
+
+void File::close()
+{
+ if (file == nullptr)
+ return;
+
+ if (fclose(file) != 0) {
+ file = nullptr;
+ throw CloseError(filePath);
+ }
+
+ file = nullptr;
+}
+
+size_t File::read(char *buffer, size_t count)
+{
+ size_t ret = fread(buffer, sizeof(char), count, file);
+
+ if (ret != count && ferror(file) != 0) {
+ throw ReadError("Error while reading file \"" + filePath + "\".");
+ }
+
+ return ret;
+}
+
+bool File::readLine(std::string &line)
+{
+ char *buffer = nullptr;
+ size_t size = 0;
+ if (getline(&buffer, &size, file) == -1) {
+ free(buffer);
+ return false;
+ }
+
+ line = buffer;
+ free(buffer);
+
+ return true;
+}
+
+std::string File::getContent()
+{
+ if (!file) {
+ throw NotOpenedException(filePath);
+ }
+
+ fseek(file, 0, SEEK_END);
+ auto fileSize = ftell(file);
+ if (fileSize == -1)
+ throw IOError(filePath);
+ rewind(file);
+ std::string content(fileSize, '\0');
+ read(&content.front(), fileSize);
+
+ return content;
+}
+
+}
--- /dev/null
+#ifndef LIBDNF_FILE_HPP
+#define LIBDNF_FILE_HPP
+
+#include "../error.hpp"
+
+#include <fstream>
+#include <memory>
+#include <string>
+
+namespace libdnf {
+
+class File
+{
+public:
+ struct IOError : Error
+ {
+ explicit IOError(const std::string &what) : Error(what) {}
+ };
+
+ struct OpenError : IOError
+ {
+ explicit OpenError(const std::string &filePath) : IOError("Cannot open file \"" + filePath + "\".") {}
+ explicit OpenError(const std::string &filePath, const std::string &detail) :
+ IOError("Cannot open file \"" + filePath + "\": " + detail) {}
+ };
+
+ struct CloseError : IOError
+ {
+ explicit CloseError(const std::string &filePath) : IOError("Cannot close file \"" + filePath + "\".") {}
+ };
+
+ struct NotOpenedException : Exception
+ {
+ explicit NotOpenedException(const std::string &filePath) :
+ Exception("File \"" + filePath + "\" is not opened.") {}
+ };
+
+ struct ReadError : IOError
+ {
+ explicit ReadError(const std::string & msg) : IOError(msg) {}
+ };
+
+ static std::unique_ptr<File> newFile(const std::string &filePath);
+
+ explicit File(const std::string &filePath);
+ File(const File&) = delete;
+ File & operator=(const File&) = delete;
+ virtual ~File();
+
+ virtual void open(const char *mode);
+ void close();
+
+ size_t read(char *buffer, size_t count);
+ bool readLine(std::string &line);
+ virtual std::string getContent();
+
+protected:
+ std::string filePath;
+ FILE *file;
+};
+
+}
+
+#endif //LIBDNF_FILE_HPP
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <GLibLogger.hpp>
+
+#include <glib.h>
+
+namespace libdnf {
+
+static inline void write_g_log(const std::string & domain, Logger::Level level, const std::string & message)
+{
+ GLogLevelFlags gLogLevel;
+ switch (level) {
+ // In GLib, the "G_LOG_LEVEL_ERROR" is more severe than "G_LOG_LEVEL_CRITICAL".
+ // In fact, the "G_LOG_LEVEL_ERROR" is always fatal. We won't use it now.
+ case Logger::Level::CRITICAL:
+ gLogLevel = G_LOG_LEVEL_CRITICAL;
+ break;
+ case Logger::Level::ERROR:
+ gLogLevel = G_LOG_LEVEL_CRITICAL;
+ break;
+
+ case Logger::Level::WARNING:
+ gLogLevel = G_LOG_LEVEL_WARNING;
+ break;
+ case Logger::Level::NOTICE:
+ gLogLevel = G_LOG_LEVEL_MESSAGE;
+ break;
+ case Logger::Level::INFO:
+ gLogLevel = G_LOG_LEVEL_INFO;
+ break;
+ case Logger::Level::DEBUG:
+ case Logger::Level::TRACE:
+ default:
+ gLogLevel = G_LOG_LEVEL_DEBUG;
+ break;
+ }
+ g_log(domain.c_str(), gLogLevel, "%s", message.c_str());
+}
+
+void GLibLogger::write(int /*source*/, Level level, const std::string & message)
+{
+ write_g_log(domain, level, message);
+}
+
+void GLibLogger::write(int /*source*/, time_t /*time*/, pid_t /*pid*/, Level level, const std::string & message)
+{
+ write_g_log(domain, level, message);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _GLIB_LOGGER_HPP_
+#define _GLIB_LOGGER_HPP_
+
+#include <logger.hpp>
+
+namespace libdnf {
+
+class GLibLogger : public Logger {
+public:
+ explicit GLibLogger(std::string domain) : domain(domain) {}
+ void write(int source, Level level, const std::string & message) override;
+ void write(int source, time_t time, pid_t pid, Level level, const std::string & message) override;
+
+private:
+ std::string domain;
+};
+
+}
+
+#endif // _GLIB_LOGGER_HPP_
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBDNF_PRESERVE_ORDER_MAP_HPP
+#define _LIBDNF_PRESERVE_ORDER_MAP_HPP
+
+#ifdef LIBDNF_UNSTABLE_API
+
+#include <cstddef>
+#include <iterator>
+#include <stdexcept>
+#include <vector>
+
+namespace libdnf {
+
+template<typename Key, typename T, class KeyEqual = std::equal_to<Key>>
+class PreserveOrderMap {
+public:
+ typedef Key key_type;
+ typedef T mapped_type;
+ typedef KeyEqual key_equal;
+ typedef std::pair<const Key, T> value_type;
+ typedef std::vector<std::pair<Key, T>> container_type;
+ typedef typename container_type::size_type size_type;
+
+ template<typename valueType, typename ContainerTypeIterator>
+ struct MyBidirIterator {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef typename PreserveOrderMap::value_type value_type;
+ typedef ptrdiff_t difference_type;
+ typedef valueType * pointer;
+ typedef valueType & reference;
+
+ explicit MyBidirIterator() = default;
+ explicit MyBidirIterator(ContainerTypeIterator ci) : ci(ci) {}
+
+ reference operator *() { return reinterpret_cast<reference>(*ci); }
+ pointer operator ->() const { return reinterpret_cast<pointer>(ci.operator->()); }
+
+ MyBidirIterator& operator ++() { ++ci; return *this; }
+ MyBidirIterator operator ++(int) { auto tmp = *this; ++*this; return tmp; }
+ MyBidirIterator& operator --() { --ci; return *this; }
+ MyBidirIterator operator --(int) { auto tmp = *this; --*this; return tmp; }
+
+ bool operator ==(const MyBidirIterator& other) const { return ci == other.ci; }
+ bool operator !=(const MyBidirIterator& other) const { return ci != other.ci; }
+
+ private:
+ friend class PreserveOrderMap;
+ ContainerTypeIterator ci;
+ };
+ typedef MyBidirIterator<value_type, typename container_type::iterator> iterator;
+ typedef MyBidirIterator<const value_type, typename container_type::const_iterator> const_iterator;
+ typedef MyBidirIterator<value_type, typename container_type::reverse_iterator> reverse_iterator;
+ typedef MyBidirIterator<const value_type, typename container_type::const_reverse_iterator> const_reverse_iterator;
+
+ bool empty() const noexcept { return items.empty(); }
+ size_type size() const noexcept { return items.size(); }
+ size_type max_size() const noexcept { return items.max_size(); }
+ void reserve(size_type newCapacity) { items.reserve(newCapacity); }
+ size_type capacity() const noexcept { return items.capacity(); }
+ void shrink_to_fit() { items.shrink_to_fit(); }
+
+ iterator begin() noexcept { return iterator(items.begin()); }
+ const_iterator begin() const noexcept { return const_iterator(items.begin()); }
+ const_iterator cbegin() const noexcept { return const_iterator(items.cbegin()); }
+ iterator end() noexcept { return iterator(items.end()); }
+ const_iterator end() const noexcept { return const_iterator(items.end()); }
+ const_iterator cend() const noexcept { return const_iterator(items.cend()); }
+ reverse_iterator rbegin() noexcept { return reverse_iterator(items.rbegin()); }
+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(items.rbegin()); }
+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(items.crbegin()); }
+ reverse_iterator rend() noexcept { return reverse_iterator(items.rend()); }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator(items.rend()); }
+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(items.crend()); }
+
+ void clear() noexcept { items.clear(); }
+
+ std::pair<iterator, bool> insert(const value_type & value)
+ {
+ auto it = find(value.first);
+ if (it == end()) {
+ it = iterator(items.insert(it.ci, value));
+ return {it, true};
+ } else {
+ return {it, false};
+ }
+ }
+
+ iterator erase(const_iterator pos) { return iterator(items.erase(pos.ci)); }
+ iterator erase(const_iterator first, const_iterator last) { return iterator(items.erase(first.ci, last.ci)); }
+
+ size_type erase(const Key & key)
+ {
+ auto it = find(key);
+ if (it == end())
+ return 0;
+ items.erase(it.ci);
+ return 1;
+ }
+
+ size_type count(const Key & key) const
+ {
+ return find(key) != end() ? 1 : 0;
+ }
+
+ iterator find(const Key & key)
+ {
+ auto it = begin();
+ while (it != end() && !KeyEqual()(it->first, key))
+ ++it;
+ return it;
+ }
+
+ const_iterator find(const Key & key) const
+ {
+ auto it = cbegin();
+ while (it != cend() && !KeyEqual()(it->first, key))
+ ++it;
+ return it;
+ }
+
+ T & operator[](const Key & key) {
+ for (auto & item : items) {
+ if (KeyEqual()(item.first, key))
+ return item.second;
+ }
+ items.push_back({key, {}});
+ return items.back().second;
+ }
+
+ T & operator[](Key && key)
+ {
+ for (auto & item : items) {
+ if (KeyEqual()(item.first, key))
+ return item.second;
+ }
+ items.push_back({std::move(key), {}});
+ return items.back().second;
+ }
+
+ T & at(const Key & key)
+ {
+ for (auto & item : items) {
+ if (KeyEqual()(item.first, key))
+ return item.second;
+ }
+ throw std::out_of_range("PreserveOrderMap::at");
+ }
+
+ const T & at(const Key & key) const
+ {
+ for (auto & item : items) {
+ if (KeyEqual()(item.first, key))
+ return item.second;
+ }
+ throw std::out_of_range("PreserveOrderMap::at");
+ }
+
+private:
+ container_type items;
+};
+
+}
+
+#endif
+
+#endif //_LIBDNF_PRESERVE_ORDER_MAP_HPP
--- /dev/null
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/bgettext.c
+ PARENT_SCOPE
+)
--- /dev/null
+# bgettext - Better gettext
+
+This is an extension of the GNU gettext.
+
+At first I tried to use the glib extension of gettext. But glib is incomplete.
+* There are macros `_()`, `C_()`. But there are missing macros for plural forms. And there is not support of plural forms with context.
+* There are macros `N_()`, `NC_()` witch only marks string for translation. There is the same problem with plural. Moreover these macros are not useable as I needed.
+* I do not want to depend on glib just for translation.
+
+## So, I wrote my extension that offers everything I need.
+
+### Extensions
+* Added macros for translation `_()`, `P_()`, `C_()`, `CP_()`.
+* Added macros for marking and encode text `M_()`, `MP_()`, `MC_()`, `MCP_()`.
+* Added macro `TM_()` for translating text encoded by `M*_()` macros.
+* Added functions for work with non-string-literals.
+
+## Description of macros for translation
+
+#### `_(msgId)`
+This macro wraps gettext/dgettext. The macro attempts to translate a text string into the user's native language, by looking up the translation in a message catalog.
+The msgId argument identifies the message to be translated. By convention, it is the English version of the message, with non-ASCII characters replaced by ASCII approximationsUses gettext to get the translation for msgId.
+If you are using the `_()` macro, you need to make sure that you pass `--keyword=_` to xgettext when extracting messages. Note that this only works with GNU gettext >= 0.15.
+##### Parameters
+`msgId` - a message id, must be a string literal
+##### Returns
+If a translation was found in one of the specified catalogs, it is converted to the locale's codeset and returned. The resulting string is statically allocated and must not be modified or freed. Otherwise msgid is returned.
+##### Example
+`label = _("This is text for translation")`
+
+#### `P_(msgId, msgIdPlural, n)`
+This macro wraps ngettext/dngettext. It is used for translate message and choose plural form.
+Plural forms are grammatical variants depending on the a number. Some languages have two forms, called singular and plural. Other languages have three or more forms.
+If you are using the `P_()` macro, you need to make sure that you pass `--keyword=P_:1,2` to xgettext when extracting messages. Note that this only works with GNU gettext >= 0.15.
+##### Parameters
+`msgId` - a message id, must be a string
+`msgIdPlural` - plural form of the message
+`n` - the quantity for which translation is needed
+##### Returns
+If a translation was found in one of the specified catalogs, the appropriate plural form is converted to the locale's codeset and returned. The resulting string is statically allocated and must not be modified or freed. In the "C" locale, or if none of the used catalogs contain a translation for msgid, the ngettext, dngettext and dcngettext functions return msgId if n == 1, or msgIdPlural if n != 1.
+##### Example
+`label = P_("There is one cat.", "There are %d cats.", n);`
+
+#### `C_(context, msgId)`
+This macro encodes context and msgId. The dgettext is used to get the translation for msgId for given context. This is useful for short strings which may need different translations, depending on the context in which they are used.
+If you are using the `C_()` macro, you need to make sure that you pass `--keyword=C_:1c,2` to xgettext when extracting messages. Note that this only works with GNU gettext >= 0.15.
+##### Parameters
+`context` - a message context, must be a string literal
+`msgId` - a message id, must be a string literal
+##### Returns
+If a translation was found in one of the specified catalogs, it is converted to the locale's codeset and returned. The resulting string is statically allocated and must not be modified or freed. Otherwise msgid is returned.
+##### Example
+`label1 = C_("Error", "Bug");`
+`label2 = C_("Insects", "Bug");`
+
+#### `CP_(context, msgId, msgIdPlural, n)`
+This is the most powerfull macro. It supports translation of message with context and plural forms. The macro encodes context and msgId and a dngettext is used internaly. See `P_()` and `C_()` macros for more informations about plural forms and context.
+If you are using the `CP_()` macro, you need to make sure that you pass `--keyword=CP_:1c,2,3` to xgettext when extracting messages. Note that this only works with GNU gettext >= 0.15.
+##### Parameters
+`context` - a message context, must be a string literal
+`msgId` - a message id, must be a string
+`msgIdPlural` - plural form of the message, must be a string literal
+`n` - the quantity for which translation is needed
+##### Returns
+If a translation was found in one of the specified catalogs, the appropriate plural form is converted to the locale's codeset and returned. The resulting string is statically allocated and must not be modified or freed. In the "C" locale, or if none of the used catalogs contain a translation for msgid, the ngettext, dngettext and dcngettext functions return msgId if n == 1, or msgIdPlural if n != 1.
+##### Example
+`label1 = CP_("Vehicles", "Bus", "Buses", n);`
+`label2 = CP_("Signal", "Bus", "Buses", n);`
+
+## Macros for text marking
+Marks a message for translation and encode it for later usage. This is useful in situations where the translated strings can't be directly used, e.g. in string array initializers. To get the translated string, use `TM_()` macro.
+If you are using these macros, you need to make sure that you pass `--keyword=M_`, `--keyword=MP_:1,2`, `--keyword=MC_:1c,2`, `--keyword=MCP_:1c,2,3` to xgettext when extracting messages. Note that this only works with GNU gettext >= 0.15.
+#### `M_(msgId)`
+#### `MP_(msgId, msgIdPlural)`
+#### `MC_(context, msgId)`
+#### `MCP_(context, msgId, msgIdPlural)`
+
+##### Example
+```
+{
+ static const char *messages[] = {
+ M_("message1"),
+ M_("message2")
+ };
+ const char *msg;
+ ...
+ msg = TM_(messages[index], 1);
+ ...
+}
+```
--- /dev/null
+/*
+ Copyright (C) 2017 Jaroslav Rohel <jrohel@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _BGETTEXT_COMMON_H_
+#define _BGETTEXT_COMMON_H_
+
+#include <libintl.h>
+#include <stddef.h>
+
+// Marks messages for translation
+#define M_(msgId) ("\001" msgId)
+#define MP_(msgId, msgIdPlural) ("\003" msgId "\00" msgIdPlural)
+#define MC_(context, msgId) ("\005" context "\004" msgId)
+#define MCP_(context, msgId, msgIdPlural) ("\007" context "\004" msgId "\00" msgIdPlural)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Preferred is use of C_() and CP_() macros. But these macros don't support non-string-literals
+// as context and msgid arguments. Next functions are intended for this case.
+const char * b_dpgettext(const char * domain, const char * context, const char * msgId);
+const char * b_dnpgettext(const char * domain, const char * context, const char * msgId, const char * msgIdPlural, unsigned long int n);
+
+const char * b_dmgettext(const char * domain, const char * markedText, unsigned long int n);
+
+// Applications should normally not use this function directly, but use the C_() and CP() macros.
+const char * b_dpgettext2(const char * domain, const char * ctxMsgId, size_t msgIdOffset);
+const char * b_dnpgettext2(const char * domain, const char * ctxMsgId, size_t msgIdOffset, const char * msgIdPlural, unsigned long int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BGETTEXT_COMMON_H_ */
--- /dev/null
+/*
+ Copyright (C) 2017 Jaroslav Rohel <jrohel@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _BGETTEXT_LIB_H_
+#define _BGETTEXT_LIB_H_
+
+#ifndef GETTEXT_DOMAIN
+#error You must define GETTEXT_DOMAIN before including bgettext-lib.h.
+#endif
+
+#include "bgettext-common.h"
+
+#define _(msgId) ((const char *)dgettext(GETTEXT_DOMAIN, msgId))
+#define P_(msgId, msgIdPlural, n) ((const char *)dngettext(GETTEXT_DOMAIN, msgId, msgIdPlural, n))
+#define C_(context, msgId) b_dpgettext2(GETTEXT_DOMAIN, context "\004" msgId, sizeof(context))
+#define CP_(context, msgId, msgIdPlural, n) ((const char *)b_dnpgettext2(GETTEXT_DOMAIN, context "\004" msgId, sizeof(context), msgIdPlural, n))
+
+#define TM_(markedMsg, n) b_dmgettext(GETTEXT_DOMAIN, markedMsg, n)
+
+#endif /* _BGETTEXT_LIB_H_ */
--- /dev/null
+/*
+ Copyright (C) 2017 Jaroslav Rohel <jrohel@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "bgettext-common.h"
+
+#include <string.h>
+
+const char *
+b_dpgettext(const char * domain, const char * context, const char * msgId)
+{
+ size_t context_len = strlen(context) + 1;
+ size_t msgId_len = strlen(msgId) + 1;
+ char ctxMsgId[context_len + msgId_len];
+
+ memcpy(ctxMsgId, context, context_len - 1);
+ ctxMsgId[context_len - 1] = '\004';
+ memcpy(ctxMsgId + context_len, msgId, msgId_len);
+
+ const char * const translation = dgettext(domain, ctxMsgId);
+
+ if (translation == ctxMsgId)
+ return msgId;
+
+ return translation;
+}
+
+const char *
+b_dpgettext2(const char * domain, const char * ctxMsgId, size_t msgIdOffset)
+{
+ const char * const translation = dgettext(domain, ctxMsgId);
+ if (translation == ctxMsgId)
+ return ctxMsgId + msgIdOffset;
+ return translation;
+}
+
+const char *
+b_dnpgettext(const char * domain, const char * context, const char * msgId, const char * msgIdPlural, unsigned long int n)
+{
+ size_t context_len = strlen(context) + 1;
+ size_t msgId_len = strlen(msgId) + 1;
+ char ctxMsgId[context_len + msgId_len];
+
+ memcpy(ctxMsgId, context, context_len - 1);
+ ctxMsgId[context_len - 1] = '\004';
+ memcpy(ctxMsgId + context_len, msgId, msgId_len);
+
+ const char * const translation = dngettext(domain, ctxMsgId, msgIdPlural, n);
+
+ if (translation == ctxMsgId)
+ return msgId;
+
+ return translation;
+}
+
+const char *
+b_dnpgettext2(const char * domain, const char * ctxMsgId, size_t msgIdOffset, const char * msgIdPlural, unsigned long int n)
+{
+ const char * const translation = dngettext(domain, ctxMsgId, msgIdPlural, n);
+ if (translation == ctxMsgId)
+ return ctxMsgId + msgIdOffset;
+ return translation;
+}
+
+const char *
+b_dmgettext(const char * domain, const char * markedMsg, unsigned long int n)
+{
+ if (*markedMsg & 0x01) {
+ const char * const msgId = markedMsg + 1;
+ if (*markedMsg & 0x02) {
+ const char * const msgIdPlural = strchr(msgId, 0) + 1;
+ const char * const translation = dngettext(domain, msgId, msgIdPlural, n);
+ if ((*markedMsg & 0x04) && n == 1 && translation == msgId)
+ return strchr(msgId, 4) + 1;
+ return translation;
+ } else {
+ const char * const translation = dgettext(domain, msgId);
+ if ((*markedMsg & 0x04) && (translation == msgId))
+ return strchr(msgId, 4) + 1;
+ return translation;
+ }
+ }
+ return markedMsg;
+}
--- /dev/null
+/*
+ Copyright (C) 2017 Jaroslav Rohel <jrohel@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _BGETTEXT_H_
+#define _BGETTEXT_H_
+
+#include "bgettext-common.h"
+
+#define _(msgId) ((const char *)gettext(msgId))
+#define P_(msgId, msgIdPlural, n) ((const char *)ngettext(msgId, msgIdPlural, n))
+#define C_(context, msgId) b_dpgettext2(NULL, context "\004" msgId, sizeof(context))
+#define CP_(context, msgId, msgIdPlural, n) ((const char *)b_dnpgettext2(NULL, context "\004" msgId, sizeof(context), msgIdPlural, n))
+
+#define TM_(markedMsg, n) b_dmgettext(NULL, markedMsg, n)
+
+#endif /* _BGETTEXT_H_ */
--- /dev/null
+/*
+ * Libdnf helper functions for file system operations
+ *
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/stat.h>
+#include <cerrno>
+#include <cstring>
+
+#include "bgettext/bgettext-lib.h"
+#include "tinyformat/tinyformat.hpp"
+#include "filesystem.hpp"
+#include "../error.hpp"
+
+namespace libdnf {
+
+/**
+ * Verify if path exists
+ * \param path file or directory path
+ * \return true if path exists
+ */
+bool
+pathExists(const char *path)
+{
+ struct stat buffer {
+ };
+ return stat(path, &buffer) == 0;
+}
+
+bool
+pathExistsOrException(const std::string & path)
+{
+ struct stat buffer;
+ if (stat(path.c_str(), &buffer) == 0) {
+ return true;
+ }
+
+ if (errno != ENOENT) {
+ throw Error("Failed to access \"" + path + "\": " + strerror(errno));
+ }
+
+ return false;
+}
+
+/**
+ * Create a directory tree for a file.
+ * When a path without a file is specified,
+ * make sure to include trailing '/'.
+ * \param path path to the directory
+ */
+void
+makeDirPath(std::string filePath)
+{
+ size_t position = 0, previous = 1; // skip leading slash
+ while ((position = filePath.find_first_of('/', previous)) != filePath.npos) {
+ std::string directory = filePath.substr(0, position++);
+ previous = position;
+ // create directory if necessary
+ if (!pathExists(directory.c_str())) {
+ int res = mkdir(directory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if (res != 0 && errno != EEXIST) {
+ auto msg = tfm::format(_("Failed to create directory \"%s\": %d - %s"),
+ directory, errno, strerror(errno));
+ throw Error(msg);
+ }
+ }
+ }
+}
+
+}
--- /dev/null
+/*
+ * Libdnf helper functions for file system operations
+ *
+ * Copyright (C) 2017-2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_FILESYSTEM_HPP
+#define LIBDNF_FILESYSTEM_HPP
+
+#include <string>
+
+namespace libdnf {
+
+bool
+pathExists(const char *path);
+
+/**
+ * Verifies if a path exists. In case of an error, throws an exception.
+ * \param path file or directory path
+ * \return true if path exists
+ */
+bool
+pathExistsOrException(const std::string & path);
+
+void
+makeDirPath(std::string filePath);
+
+}
+
+#endif
--- /dev/null
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/iniparser.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "iniparser.hpp"
+
+constexpr char DELIMITER = '\n';
+
+const char * IniParser::CantOpenFile::what() const noexcept
+{
+ return "IniParser: Can't open file";
+}
+
+const char * IniParser::MissingSectionHeader::what() const noexcept
+{
+ return "IniParser: Missing section header";
+}
+
+const char * IniParser::MissingBracket::what() const noexcept
+{
+ return "IniParser: Missing ']'";
+}
+
+const char * IniParser::EmptySectionName::what() const noexcept
+{
+ return "IniParser: Empty section name";
+}
+
+const char * IniParser::TextAfterSection::what() const noexcept
+{
+ return "IniParser: Text after section";
+}
+
+const char * IniParser::IllegalContinuationLine::what() const noexcept
+{
+ return "IniParser: Illegal continuation line";
+}
+
+const char * IniParser::MissingKey::what() const noexcept
+{
+ return "IniParser: Missing key";
+}
+
+const char * IniParser::MissingEqual::what() const noexcept
+{
+ return "IniParser: Missing '='";
+}
+
+IniParser::IniParser(const std::string & filePath)
+: is(new std::ifstream(filePath))
+{
+ if (!(*is))
+ throw CantOpenFile();
+ is->exceptions(std::ifstream::badbit);
+ lineNumber = 0;
+ lineReady = false;
+}
+
+IniParser::IniParser(std::unique_ptr<std::istream> && inputStream)
+: is(std::move(inputStream))
+{
+ if (!(*is))
+ throw CantOpenFile();
+ is->exceptions(std::ifstream::badbit);
+ lineNumber = 0;
+ lineReady = false;
+}
+
+void IniParser::trimValue() noexcept {
+ auto end = value.find_last_not_of(DELIMITER);
+ if (end != value.npos)
+ value.resize(end + 1);
+ if (value.length() > 1 &&
+ value.front() == value.back() &&
+ (value.front() == '\"' || value.front() == '\'')) {
+ value.erase(--value.end());
+ value.erase(value.begin());
+ }
+}
+
+IniParser::ItemType IniParser::next()
+{
+ bool previousLineWithKeyVal = false;
+ rawItem.clear();
+ while (lineReady || !is->eof()) {
+ if (!lineReady) {
+ std::getline(*is, line, DELIMITER);
+ ++lineNumber;
+ lineReady = true;
+ }
+
+ // remove UTF-8 BOM
+ if (lineNumber == 1 && line.length() >= 3 &&
+ static_cast<unsigned char>(line[0]) == 0xEF &&
+ static_cast<unsigned char>(line[1]) == 0xBB &&
+ static_cast<unsigned char>(line[2]) == 0xBF)
+ line.erase(0, 3);
+
+ if (line.length() == 0 || line[0] == '#' || line[0] == ';') {// do not support [rR][eE][mM] comment
+ if (previousLineWithKeyVal) {
+ trimValue();
+ return ItemType::KEY_VAL;
+ }
+ if (line.length() == 0) {
+ if (is->eof())
+ return ItemType::END_OF_INPUT;
+ lineReady = false;
+ rawItem = DELIMITER;
+ return ItemType::EMPTY_LINE;
+ }
+ rawItem = line + DELIMITER;
+ lineReady = false;
+ return ItemType::COMMENT_LINE;
+ }
+ auto start = line.find_first_not_of(" \t\r");
+ if (start == std::string::npos) {
+ if (previousLineWithKeyVal) {
+ value += DELIMITER;
+ rawItem += line + DELIMITER;
+ lineReady = false;
+ continue;
+ }
+ rawItem = line + DELIMITER;
+ lineReady = false;
+ return ItemType::EMPTY_LINE;
+ }
+ auto end = line.find_last_not_of(" \t\r");
+
+ if (previousLineWithKeyVal && (start == 0 || line[start] == '[')) {
+ trimValue();
+ return ItemType::KEY_VAL;
+ }
+
+ if (line[start] == '[') {
+ auto endSectPos = line.find("]", ++start);
+ if (endSectPos == line.npos)
+ throw MissingBracket(lineNumber);
+ else if (endSectPos == start)
+ throw EmptySectionName(lineNumber);
+ for (auto idx = endSectPos + 1; idx < end; ++idx)
+ {
+ auto ch = line[idx];
+ if (ch == '#' || ch == ';')
+ break;
+ if (ch != ' ' && ch != '\t' && ch != '\r')
+ throw TextAfterSection(lineNumber);
+ }
+ this->section = line.substr(start, endSectPos - start);
+ rawItem = line + DELIMITER;
+ lineReady = false;
+ return ItemType::SECTION;
+ }
+
+ if (section.empty())
+ throw MissingSectionHeader(lineNumber);
+
+ if (start > 0) {
+ if (!previousLineWithKeyVal)
+ throw IllegalContinuationLine(lineNumber);
+ value += DELIMITER + line.substr(start, end - start + 1);
+ rawItem += line + DELIMITER;
+ lineReady = false;
+ } else {
+ if (line[start] == '=')
+ throw MissingKey(lineNumber);
+ auto eqlpos = line.find_first_of("=");
+ if (eqlpos == std::string::npos)
+ throw MissingEqual(lineNumber);
+ auto endkeypos = line.find_last_not_of(" \t", eqlpos - 1);
+ auto valuepos = line.find_first_not_of(" \t", eqlpos + 1);
+ key = line.substr(start, endkeypos - start + 1);
+ if (valuepos != line.npos)
+ value = line.substr(valuepos, end - valuepos + 1);
+ else
+ value.clear();
+ previousLineWithKeyVal = true;
+ rawItem = line + DELIMITER;
+ lineReady = false;
+ }
+ }
+ trimValue();
+ return previousLineWithKeyVal ? ItemType::KEY_VAL : ItemType::END_OF_INPUT;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _INIPARSER_HPP
+#define _INIPARSER_HPP
+
+#include <exception>
+#include <fstream>
+#include <memory>
+#include <string>
+
+/**
+* @class IniParser
+*
+* @brief Simple .INI file parser
+*
+* The goal is to be compatible with dnf / yum .ini configuration files.
+*/
+class IniParser {
+public:
+ struct Exception : public std::exception {
+ Exception(int lineNumber) : lineNumber(lineNumber) {}
+ Exception() : lineNumber(0) {}
+ int getLineNumber() const noexcept { return lineNumber; }
+ protected:
+ int lineNumber;
+ };
+ struct CantOpenFile : public Exception {
+ CantOpenFile() {}
+ const char * what() const noexcept override;
+ };
+ struct MissingSectionHeader : public Exception {
+ MissingSectionHeader(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct MissingBracket : public Exception {
+ MissingBracket(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct EmptySectionName : public Exception {
+ EmptySectionName(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct TextAfterSection : public Exception {
+ TextAfterSection(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct IllegalContinuationLine : public Exception {
+ IllegalContinuationLine(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct MissingKey : public Exception {
+ MissingKey(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+ struct MissingEqual : public Exception {
+ MissingEqual(int lineNumber) : Exception(lineNumber) {}
+ const char * what() const noexcept override;
+ };
+
+ enum class ItemType {
+ SECTION, // [section_name]
+ KEY_VAL, // key = value, (multiline value supported)
+ COMMENT_LINE, // line starting with '#' or ';' character
+ EMPTY_LINE, // zero length or only contains whitespace characters
+ END_OF_INPUT
+ };
+
+ IniParser(const std::string & filePath);
+ IniParser(std::unique_ptr<std::istream> && inputStream);
+ /**
+ * @brief Parse one item from input file
+ *
+ * Returns type of parsed item. Parsed values can be obtained by methods
+ * getSection(), getKey(), getValue().
+ *
+ * @return IniParser::ItemType Type of parsed value
+ */
+ ItemType next();
+ const std::string & getSection() const noexcept;
+ const std::string & getKey() const noexcept;
+ std::string & getKey() noexcept;
+ const std::string & getValue() const noexcept;
+ std::string & getValue() noexcept;
+ const std::string & getRawItem() const noexcept;
+ std::string & getRawItem() noexcept;
+ const std::string & getLine() const noexcept;
+ void clearLine() noexcept;
+ void trimValue() noexcept;
+
+private:
+ std::unique_ptr<std::istream> is;
+ int lineNumber;
+ std::string section;
+ std::string key;
+ std::string value;
+ std::string rawItem;
+ std::string line;
+ bool lineReady;
+};
+
+inline const std::string & IniParser::getSection() const noexcept { return section; }
+inline const std::string & IniParser::getKey() const noexcept { return key; }
+inline std::string & IniParser::getKey() noexcept { return key; }
+inline const std::string & IniParser::getValue() const noexcept { return value; }
+inline std::string & IniParser::getValue() noexcept { return value; }
+inline const std::string & IniParser::getRawItem() const noexcept { return rawItem; }
+inline std::string & IniParser::getRawItem() noexcept { return rawItem; }
+inline const std::string & IniParser::getLine() const noexcept { return line; }
+inline void IniParser::clearLine() noexcept { line.clear(); }
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <logger.hpp>
+
+namespace libdnf {
+
+constexpr const char * Logger::levelCStr[];
+
+void Logger::write(int source, Level level, const std::string & message)
+{
+ write(source, time(NULL), getpid(), level, message);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LOGGER_HPP_
+#define _LOGGER_HPP_
+
+#include <string>
+
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+namespace libdnf {
+
+class Logger {
+public:
+ enum class Level {CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, TRACE};
+ static constexpr const char * levelToCStr(Level level) noexcept { return level<Level::CRITICAL || level>Level::TRACE ? "USER" : levelCStr[static_cast<int>(level)]; }
+
+ enum Source {LOG_SOURCE_LIBDNF = 0, LOG_SOURCE_LIBREPO = 1};
+
+ void critical(const std::string & message) { write(Level::CRITICAL, message); }
+ void error(const std::string & message) { write(Level::ERROR, message); }
+ void warning(const std::string & message) { write(Level::WARNING, message); }
+ void notice(const std::string & message) { write(Level::NOTICE, message); }
+ void info(const std::string & message) { write(Level::INFO, message); }
+ void debug(const std::string & message) { write(Level::DEBUG, message); }
+ void trace(const std::string & message) { write(Level::TRACE, message); }
+
+ void critical(int source, const std::string & message) { write(source, Level::CRITICAL, message); }
+ void error(int source, const std::string & message) { write(source, Level::ERROR, message); }
+ void warning(int source, const std::string & message) { write(source, Level::WARNING, message); }
+ void notice(int source, const std::string & message) { write(source, Level::NOTICE, message); }
+ void info(int source, const std::string & message) { write(source, Level::INFO, message); }
+ void debug(int source, const std::string & message) { write(source, Level::DEBUG, message); }
+ void trace(int source, const std::string & message) { write(source, Level::TRACE, message); }
+
+ void write(Level level, const std::string & message) { write(LOG_SOURCE_LIBDNF, level, message); }
+ void write(time_t time, pid_t pid, Level level, const std::string & message) { write(LOG_SOURCE_LIBDNF, time, pid, level, message); }
+
+ virtual void write(int source, Level level, const std::string & message);
+ virtual void write(int source, time_t time, pid_t pid, Level level, const std::string & message) = 0;
+ virtual ~Logger() = default;
+
+private:
+ static constexpr const char * levelCStr[]{"CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", "TRACE"};
+};
+
+class NullLogger : public Logger {
+public:
+ void write(int, Level, const std::string &) override {}
+ void write(int, time_t, pid_t, Level, const std::string &) override {}
+};
+
+}
+
+#endif // _LOGGER_HPP_
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "os-release.hpp"
+#include "File.hpp"
+#include "utils.hpp"
+#include "libdnf/dnf-context.h"
+#include "libdnf/log.hpp"
+#include "tinyformat/tinyformat.hpp"
+
+#include <algorithm>
+#include <array>
+#include <map>
+#include <rpm/rpmlib.h>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace libdnf {
+
+// sorted by precedence (see os-release(5) for details)
+static const std::array<const std::string, 2>
+paths = {"/etc/os-release", "/usr/lib/os-release"};
+
+std::map<std::string, std::string> getOsReleaseData()
+{
+ std::map<std::string, std::string> result;
+
+ // find the first existing file path
+ auto it = std::find_if(paths.begin(), paths.end(), libdnf::filesystem::exists);
+ if (it == paths.end())
+ throw std::runtime_error("os-release file not found");
+ std::string path = *it;
+
+ auto file = libdnf::File::newFile(path);
+ file->open("r");
+ std::string line;
+ while (file->readLine(line)) {
+ // remove trailing spaces and newline
+ line.erase(line.find_last_not_of(" \n") + 1);
+
+ // skip empty lines
+ if (line.empty()) continue;
+ // skip comments
+ if (line.front() == '#') continue;
+
+ // split string by '=' into key and value
+ auto pos = line.find('=');
+ if (pos == line.npos)
+ throw std::runtime_error("Invalid format (missing '='): " + line);
+ auto key = string::trim(line.substr(0, pos));
+ auto value = string::trim(line.substr(pos + 1, line.length()));
+
+ // remove quotes if present
+ if (!value.empty() && value.front() == '"' && value.back() == '"') {
+ value = value.substr(1, value.length() - 2);
+ }
+
+ result.insert({key, value});
+ }
+ return result;
+}
+
+static void initLibRpm()
+{
+ // call dnf_context_globals_init to ensure this only happens once
+ g_autoptr(GError) local_error = NULL;
+ if (!dnf_context_globals_init(&local_error))
+ throw std::runtime_error(local_error->message);
+}
+
+static std::string getBaseArch()
+{
+ const char *value;
+ initLibRpm();
+ rpmGetArchInfo(&value, NULL);
+ value = find_base_arch(value);
+ return value ? std::string(value) : "";
+}
+
+static std::string getCanonOs()
+{
+ const char *value;
+ initLibRpm();
+ rpmGetOsInfo(&value, NULL);
+ return value;
+}
+
+std::string getUserAgent(const std::map<std::string, std::string> & osReleaseData)
+{
+ std::ostringstream oss;
+ auto logger(Log::getLogger());
+
+ oss << USER_AGENT;
+ std::string fallback = oss.str();
+
+ if (!osReleaseData.count("NAME") || !osReleaseData.count("VERSION_ID")) {
+ logger->debug(tfm::format(
+ "User-Agent: falling back to '%s': missing NAME or VERSION_ID",
+ fallback
+ ));
+ return fallback;
+ }
+ std::string name = osReleaseData.at("NAME");
+ std::string version = osReleaseData.at("VERSION_ID");
+ std::string variant = "generic";
+ if (osReleaseData.count("VARIANT_ID"))
+ variant = osReleaseData.at("VARIANT_ID");
+
+ std::string canon = getCanonOs();
+ std::string arch = getBaseArch();
+ if (canon.empty() || arch.empty()) {
+ logger->debug(tfm::format(
+ "User-Agent: falling back to '%s': could not detect OS or basearch",
+ fallback
+ ));
+ return fallback;
+ }
+
+ oss << " (" << name << " " << version << "; " << variant << "; " << canon
+ << "." << arch << ")";
+
+ std::string result = oss.str();
+ logger->debug(tfm::format("User-Agent: constructed: '%s'", result));
+ return result;
+}
+
+std::string getUserAgent()
+{
+ std::map<std::string, std::string> osdata;
+ try {
+ osdata = getOsReleaseData();
+ } catch (std::exception & ex) {
+ Log::getLogger()->debug(ex.what());
+ }
+ return getUserAgent(osdata);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _OS_RELEASE_HPP_
+#define _OS_RELEASE_HPP_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#define USER_AGENT "libdnf"
+
+namespace libdnf {
+
+/**
+ * @brief Parse the os-release file and return its contents in a map.
+ *
+ * The file /etc/os-release takes precedence over /usr/lib/os-release which
+ * acts as a fallback should the former not exist (see os-release(5) for
+ * details).
+ *
+ * @return a map containing os-release data
+ */
+std::map<std::string, std::string>
+getOsReleaseData();
+
+/**
+ * @brief Construct and return the User-Agent string for libdnf to send in HTTP
+ * headers.
+ *
+ * The format returned is as follows:
+ *
+ * libdnf (NAME VERSION_ID; VARIANT_ID; OS.BASEARCH)
+ *
+ * where NAME, VERSION_ID and VARIANT_ID are OS identifiers read from the
+ * passed os-release data, and OS and BASEARCH are the canonical OS name and
+ * base architecture, respectively, detected using RPM.
+ *
+ * @param osReleaseData a map containing os-release data (will be loaded from
+ * disk if not specified)
+ * @return a User-Agent string
+ */
+std::string
+getUserAgent(const std::map<std::string, std::string> & osReleaseData);
+std::string
+getUserAgent();
+
+}
+
+#endif
--- /dev/null
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/regex.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "regex.hpp"
+
+#include <string.h>
+
+Regex::Regex(const char * regex, int flags)
+{
+ auto errCode = regcomp(&exp, regex, flags);
+ if (errCode != 0) {
+ auto size = regerror(errCode, &exp, nullptr, 0);
+ if (size) {
+ std::string msg(size, '\0');
+ regerror(errCode, &exp, &msg.front(), size);
+ throw LibraryException(errCode, msg);
+ }
+ throw LibraryException(errCode, "");
+ }
+}
+
+Regex &
+Regex::operator=(Regex && src) noexcept
+{
+ free();
+ freed = src.freed;
+ exp = src.exp;
+ src.freed = true;
+ return *this;
+}
+
+Regex::Result
+Regex::match(const char * str, bool copyStr, std::size_t count) const
+{
+ if (freed)
+ throw InvalidException();
+ auto maxMatches = exp.re_nsub + 1;
+ auto size = count < maxMatches ? count : maxMatches;
+ Result ret(str, copyStr, size);
+ ret.matched = regexec(&exp, str, size, ret.matches.data(), 0) == 0;
+ return ret;
+}
+
+Regex::Result::Result(const Regex::Result& src)
+: sourceOwner(src.sourceOwner), matched(src.matched), matches(src.matches)
+{
+ if (sourceOwner) {
+ auto tmp = new char[strlen(src.source) + 1];
+ this->source = strcpy(tmp, src.source);
+ } else
+ this->source = src.source;
+}
+
+Regex::Result::Result(Regex::Result && src)
+: source(src.source), sourceOwner(src.sourceOwner)
+, matched(src.matched), matches(std::move(src.matches))
+{
+ src.source = nullptr;
+ src.sourceOwner = false;
+ src.matched = false;
+}
+
+Regex::Result::Result(const char * source, bool copySource, std::size_t count)
+: sourceOwner(copySource), matched(false), matches(count)
+{
+ if (copySource) {
+ auto tmp = new char[strlen(source) + 1];
+ this->source = strcpy(tmp, source);
+ } else
+ this->source = source;
+}
+
+std::string
+Regex::Result::getMatchedString(std::size_t index) const
+{
+ if (matched && index < matches.size() && matches[index].rm_so != NOT_FOUND) {
+ auto subexpr_len = matches[index].rm_eo - matches[index].rm_so;
+ if (subexpr_len > 0)
+ return std::string(source + matches[index].rm_so, subexpr_len);
+ }
+ return "";
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _REGEX_HPP
+#define _REGEX_HPP
+
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include <regex.h>
+
+/**
+* @brief Wrapper of POSIX C regular expression implementation "regex.h".
+* Regex class uses POSIX functions regcomp(), regexec(), regerror(), regfree()
+* and structures regex_t, regmatch_t internally.
+*/
+class Regex {
+public:
+ class Exception : public std::runtime_error {
+ public:
+ Exception(const std::string & msg) : runtime_error(msg) {}
+ Exception(const char * msg) : runtime_error(msg) {}
+ };
+
+ /**
+ * @brief Delivers error code from regcomp() and coresponding error message string
+ */
+ class LibraryException : public Exception {
+ public:
+ LibraryException(int code, const std::string & msg) : Exception(msg), ecode(code) {}
+ LibraryException(int code, const char * msg) : Exception(msg), ecode(code) {}
+ int code() const noexcept { return ecode; }
+ protected:
+ int ecode;
+ };
+
+ class InvalidException : public Exception {
+ public:
+ InvalidException()
+ : Exception("Regex object unusable. Its value was moved to another Regex object.") {}
+ };
+
+ /**
+ * @brief Result of Regex::match() method
+ * Contains copy or pointer to matched string and information
+ * regarding the location of any matched substrings.
+ */
+ class Result {
+ public:
+ Result(const Result & src);
+ Result(Result && src);
+ static constexpr int NOT_FOUND = -1;
+
+ /**
+ * @brief Returns true if contains copy of matched string
+ * @return bool
+ */
+ bool hasSourceCopy() const noexcept;
+
+ /**
+ * @brief Returns true if string is matching
+ * @return bool
+ */
+ bool isMatched() const noexcept;
+
+ /**
+ * @brief Returns number of matched substrings in Result
+ * @return std::size_t
+ */
+ std::size_t getMatchedCount() const noexcept;
+
+ /**
+ * @brief Returns start offset of the matched substring
+ * @param index index of matched substring
+ * @return byte offset from start of string to start of substring or Result::NOT_FOUND
+ */
+ int getMatchStartOffset(std::size_t index) const noexcept;
+
+ /**
+ * @brief Returns end offset of the matched substring
+ * @param index index of matched substring
+ * @return byte offset from start of string of the first character after the end of substring
+ * or Result::NOT_FOUND
+ */
+ int getMatchEndOffset(std::size_t index) const noexcept;
+
+ /**
+ * @brief Returns length of the matched substring
+ * @param index index of matched substring
+ * @return length of matched substring or Result::NOT_FOUND
+ */
+ int getMatchedLen(std::size_t index) const noexcept;
+
+ /**
+ * @brief Returns the matched substring
+ * @param index Index of matched substring
+ * @return matched substring or ""
+ */
+ std::string getMatchedString(std::size_t index) const;
+ ~Result();
+ private:
+ friend class Regex;
+ Result(const char * source, bool copySource, std::size_t count);
+ const char * source;
+ bool sourceOwner;
+ bool matched;
+ std::vector<regmatch_t> matches;
+ };
+
+ /**
+ * @brief Constructs new Regex object
+ * Compiles input regular expression string using POSIX regcomp() function.
+ * Input parameters regex and flags corespond to regcomp() parameters.
+ *
+ * @param regex regular expression
+ * @param flags compile flags
+ */
+ Regex(const char * regex, int flags);
+ Regex(const Regex & src) = delete;
+ Regex(Regex && src) noexcept;
+
+ Regex & operator=(const Regex & src) = delete;
+ Regex & operator=(Regex && src) noexcept;
+
+ /**
+ * @brief Returns number of parenthesized subexpressions
+ * Coresponds to re_nsub in POSIX regex_t structure.
+ *
+ * @return number of parenthesized subexpressions
+ */
+ std::size_t getSubexprCount() const;
+
+ /**
+ * @brief Match input string to precompiled regular expression
+ * POSIX regexec() function is used.
+ *
+ * @param str string to match
+ * @return true if string is matched
+ */
+ bool match(const char * str) const;
+
+ /**
+ * @brief Match input string to precompiled regular expression
+ * POSIX regexec() function is used.
+ *
+ * @param str string to match
+ * @param copyStr if is true then copy of str will be done into the Result,
+ * copy only pointer otherwise
+ * @param count Max number of matches we want to get
+ * @return object providing information regarding the location of any matches
+ */
+ Result match(const char * str, bool copyStr, std::size_t count) const;
+ ~Regex();
+private:
+ void free() noexcept;
+ bool freed{false};
+ regex_t exp;
+};
+
+inline Regex::Regex(Regex && src) noexcept
+: freed(src.freed), exp(src.exp)
+{
+ src.freed = true;
+}
+
+inline std::size_t Regex::getSubexprCount() const
+{
+ if (freed)
+ throw InvalidException();
+ return exp.re_nsub;
+}
+
+inline bool Regex::match(const char * str) const
+{
+ if (freed)
+ throw InvalidException();
+ return regexec(&exp, str, 0, nullptr, 0) == 0;
+}
+
+inline Regex::~Regex()
+{
+ free();
+}
+
+inline void Regex::free() noexcept
+{
+ if (!freed)
+ regfree(&exp);
+}
+
+inline Regex::Result::~Result()
+{
+ if (sourceOwner)
+ delete[] source;
+}
+
+inline bool Regex::Result::hasSourceCopy() const noexcept
+{
+ return sourceOwner;
+}
+
+inline bool Regex::Result::isMatched() const noexcept
+{
+ return matched;
+}
+
+inline std::size_t Regex::Result::getMatchedCount() const noexcept
+{
+ return matches.size();
+}
+
+inline int Regex::Result::getMatchStartOffset(std::size_t index) const noexcept
+{
+ return matched && index < matches.size() ? matches[index].rm_so : NOT_FOUND;
+}
+
+inline int Regex::Result::getMatchEndOffset(std::size_t index) const noexcept
+{
+ return matched && index < matches.size() ? matches[index].rm_eo : NOT_FOUND;
+}
+
+inline int Regex::Result::getMatchedLen(std::size_t index) const noexcept
+{
+ return matched && index < matches.size() && matches[index].rm_so != NOT_FOUND ?
+ matches[index].rm_eo - matches[index].rm_so : NOT_FOUND;
+}
+
+#endif
--- /dev/null
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Column.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Line.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Table.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_CELL_HPP
+#define LIBDNF_CELL_HPP
+
+#include <libsmartcols/libsmartcols.h>
+#include <cerrno>
+#include <string>
+#include <stdexcept>
+
+class Cell
+{
+public:
+ explicit Cell(struct libscols_cell *cell) : cell(cell) {}
+
+ void reset() { scols_reset_cell(cell); }
+
+ int getFlags() const noexcept { return scols_cell_get_flags(cell); }
+ int getAlignment() const noexcept { return scols_cell_get_alignment(cell); }
+ const char *getData() const { return scols_cell_get_data(cell); }
+ const char *getColor() const noexcept { return scols_cell_get_color(cell); }
+ void *getUserdata() const { return scols_cell_get_userdata(cell); }
+
+ void setData(const std::string &data);
+ void setColor(const std::string &color);
+ void setFlags(int flags);
+ void setUserdata(void *data);
+
+ bool operator==(const Cell &cell) const { return scols_cmpstr_cells(this->cell, cell.cell, nullptr) == 0; }
+
+private:
+ struct libscols_cell *cell;
+};
+
+inline void Cell::setData(const std::string &data)
+{
+ if (scols_cell_set_data(cell, data.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set data");
+}
+
+inline void Cell::setColor(const std::string &color)
+{
+ if (scols_cell_set_color(cell, color.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set color");
+}
+
+inline void Cell::setFlags(int flags)
+{
+ if (scols_cell_set_flags(cell, flags) == -EINVAL)
+ throw std::runtime_error("Cannot set flags");
+}
+
+inline void Cell::setUserdata(void *data)
+{
+ if (scols_cell_set_userdata(cell, data) == -EINVAL)
+ throw std::runtime_error("Cannot set userdata");
+}
+
+#endif //LIBDNF_CELL_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Column.hpp"
+
+size_t wrapNewlineChunksize(const struct libscols_column *column, const char *data, void *userdata) { return scols_wrapnl_chunksize(column, data, userdata); }
+char *wrapNewlineNextchunk(const struct libscols_column *column, char *data, void *userdata) { return scols_wrapnl_nextchunk(column, data, userdata); }
+
+std::shared_ptr<Cell> Column::getHeader() const
+{
+ return std::make_shared<Cell>(scols_column_get_header(column));
+}
+
+void Column::setCompareFunction(int (*function)(struct libscols_cell *, struct libscols_cell *, void *), void *data)
+{
+ scols_column_set_cmpfunc(column, function, data);
+}
+
+void Column::setWrapFunction(size_t (*wrapChunksize)(const struct libscols_column *, const char *, void *),
+ char *(*wrapNextchunk)(const struct libscols_column *, char *, void *), void *userdata)
+{
+ scols_column_set_wrapfunc(column, wrapChunksize, wrapNextchunk, userdata);
+}
+
+void Column::setWrap(bool enable)
+{
+ int formerFlags = scols_column_get_flags(column);
+ int current = formerFlags & SCOLS_FL_WRAP;
+ if (!current && enable)
+ scols_column_set_flags(column, formerFlags | SCOLS_FL_WRAP);
+ else if (current && !enable)
+ scols_column_set_flags(column, formerFlags ^ SCOLS_FL_WRAP);
+}
+
+void Column::setColor(const std::string &color)
+{
+ if (scols_column_set_color(column, color.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set color");
+}
+
+void Column::setFlags(int flags)
+{
+ if (scols_column_set_flags(column, flags) == -EINVAL)
+ throw std::runtime_error("Cannot set flags");
+}
+
+void Column::setSafechars(const std::string &safe)
+{
+ if (scols_column_set_safechars(column, safe.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set safechars");
+}
+
+void Column::setWidthHint(double hint)
+{
+ if (scols_column_set_whint(column, hint) == -EINVAL)
+ throw std::runtime_error("Cannot set width hint");
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_COLUMN_HPP
+#define LIBDNF_COLUMN_HPP
+
+#include "Cell.hpp"
+
+#include <memory>
+#include <libsmartcols/libsmartcols.h>
+#include <cerrno>
+
+size_t wrapNewlineChunksize(const struct libscols_column *column, const char *data, void *userdata);
+char *wrapNewlineNextchunk(const struct libscols_column *column, char *data, void *userdata);
+
+class Line;
+class Table;
+
+class Column
+{
+ friend class Line;
+ friend class Table;
+
+public:
+ explicit Column(struct libscols_column *column) : column(column) { scols_ref_column(column); }
+ Column(Column &column) { this->column = scols_copy_column(column.column); }
+ ~Column() { scols_unref_column(column); }
+
+ bool isTree() const noexcept { return scols_column_is_tree(column) == 1; }
+ bool isTrunc() const noexcept { return scols_column_is_trunc(column) == 1; }
+ bool isRight() const noexcept { return scols_column_is_right(column) == 1; }
+ bool isStrictWidth() const noexcept { return scols_column_is_strict_width(column) == 1; }
+ bool isHidden() const noexcept { return scols_column_is_hidden(column) == 1; }
+ bool isNoextremes() const noexcept { return scols_column_is_noextremes(column) == 1; }
+ bool isWrap() const noexcept { return scols_column_is_wrap(column) == 1; }
+ bool isCustomwrap() const noexcept { return scols_column_is_customwrap(column) == 1; }
+
+ int getFlags() const noexcept { return scols_column_get_flags(column); }
+ double getWidthHint() const { return scols_column_get_whint(column); }
+ size_t getWidth() const noexcept { return scols_column_get_width(column); }
+ std::string getSafechars() const noexcept { return scols_column_get_safechars(column); }
+ std::string getColor() const noexcept { return scols_column_get_color(column); }
+ std::shared_ptr<Cell> getHeader() const;
+
+ void setWrap(bool enable);
+ void setColor(const std::string &color);
+ void setFlags(int flags);
+ void setSafechars(const std::string &safe);
+ void setWidthHint(double hint);
+
+
+ void setCompareFunction(int (*function)(struct libscols_cell *a, struct libscols_cell *b, void *), void *data);
+ void setWrapFunction(size_t (*wrapChunksize)(const struct libscols_column *, const char *, void *),
+ char *(*wrapNextchunk)(const struct libscols_column *, char *, void *),
+ void *userdata);
+
+ void setNewlineWrapFunction() { setWrapFunction(wrapNewlineChunksize, wrapNewlineNextchunk, nullptr); }
+
+private:
+ struct libscols_column *column;
+};
+
+
+#endif //LIBDNF_COLUMN_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Line.hpp"
+
+std::shared_ptr<Line> Line::nextChild(struct libscols_iter *iter)
+{
+ struct libscols_line *scolsLine;
+ scols_line_next_child(line, iter, &scolsLine);
+
+ return std::make_shared<Line>(scolsLine);
+}
+
+void Line::referColumnData(Column *column, char *data)
+{
+ scols_line_refer_column_data(line, column->column, data);
+}
+
+std::shared_ptr<Cell> Line::getColumnCell(Column *column) const
+{
+ return std::make_shared<Cell>(scols_line_get_column_cell(line, column->column));
+}
+
+void Line::setColumnData(const std::shared_ptr<Column> &column, const std::string &data)
+{
+ setColumnData(column.get(), data);
+}
+
+void Line::setColumnData(Column *column, const std::string &data)
+{
+ scols_line_set_column_data(line, column->column, data.c_str());
+}
+
+std::shared_ptr<Cell> Line::getCell(size_t n) const
+{
+ if (n >= getCellCount()) {
+ std::string message = "Out of bound, Index: " + n;
+ message += " Size: " + getCellCount();
+ throw std::out_of_range(message);
+ }
+ return std::make_shared<Cell>(scols_line_get_cell(line, n));
+}
+
+void Line::setUserdata(void *data)
+{
+ if (scols_line_set_userdata(line, data) == -EINVAL)
+ throw std::runtime_error("Cannot set userdata");
+}
+
+void Line::setColor(const std::string &color)
+{
+ if (scols_line_set_color(line, color.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set color");
+}
+
+void Line::setData(size_t n, const std::string &data)
+{
+ if (scols_line_set_data(line, n, data.c_str()) == -EINVAL)
+ throw std::runtime_error("Cannot set data");
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_LINE_HPP
+#define LIBDNF_LINE_HPP
+
+#include "Cell.hpp"
+#include "Column.hpp"
+
+#include <memory>
+#include <libsmartcols/libsmartcols.h>
+
+class Table;
+
+class Line
+{
+ friend class Table;
+
+public:
+ explicit Line(struct libscols_line *line) : line(line) { scols_ref_line(line); }
+ Line(const Line &line) { this->line = scols_copy_line(line.line); }
+ ~Line() { scols_unref_line(line); }
+
+ void allocCells(size_t n) { scols_line_alloc_cells(line, n); }
+ void freeCells() { scols_line_free_cells(line); }
+
+ void addChild(Line *child) { scols_line_add_child(line, child->line); }
+ void removeChild(Line *child) { scols_line_remove_child(line, child->line); }
+ std::shared_ptr<Line> nextChild(struct libscols_iter *iter);
+
+ void referData(size_t n, char *data) { scols_line_refer_data(line, n, data); }
+ void referColumnData(Column *column, char *data);
+
+ bool hasChildren() const noexcept { return scols_line_has_children(line) == 1; }
+ bool isAncestor(Line *parent) const noexcept { return scols_line_is_ancestor(line, parent->line) == 1; }
+
+ size_t getCellCount() const noexcept { return scols_line_get_ncells(line); }
+ const char *getColor() const { return scols_line_get_color(line); }
+ std::shared_ptr<Cell> getCell(size_t n) const;
+ std::shared_ptr<Cell> getColumnCell(const std::shared_ptr<Column> &column) const { return getColumnCell(column.get()); }
+ std::shared_ptr<Cell> getColumnCell(Column *column) const;
+ std::shared_ptr<Line> getParent() const { return std::make_shared<Line>(scols_line_get_parent(line)); }
+ void *getUserdata() const { return scols_line_get_userdata(line); }
+
+ void setUserdata(void *data);
+ void setColor(const std::string &color);
+ void setData(size_t n, const std::string &data);
+ void setColumnData(const std::shared_ptr<Column> &column, const std::string &data);
+ void setColumnData(Column *column, const std::string &data);
+
+
+private:
+ struct libscols_line *line;
+};
+
+
+#endif //LIBDNF_LINE_HPP
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Table.hpp"
+
+Table::Table()
+ : table(scols_new_table())
+{
+ if (!table) {
+ throw std::runtime_error("Could not create table");
+ }
+}
+
+void Table::setColumnSeparator(const std::string &separator)
+{
+ scols_table_set_column_separator(table, separator.c_str());
+}
+
+std::shared_ptr<Column> Table::getColumn(size_t n) const
+{
+ if (columns.size() < n) {
+ std::string message = "Out of bounds. Index: " + n;
+ message += " Size: " + columns.size();
+ throw std::out_of_range(message);
+ }
+ return columns[n];
+}
+
+std::shared_ptr<Line> Table::getLine(size_t n) const
+{
+ if (lines.size() < n) {
+ std::string message = "Out of bounds. Index: " + n;
+ message += " Size: " + lines.size();
+ throw std::out_of_range(message);
+ }
+ return lines[n];
+}
+
+void Table::moveColumn(const std::shared_ptr<Column> &before, const std::shared_ptr<Column> &toMove)
+{
+ scols_table_move_column(table, before->column, toMove->column);
+}
+
+std::shared_ptr<Column> Table::newColumn(const std::string &name, double widthHint, int flags)
+{
+ auto smartColsColumn = scols_table_new_column(table, name.c_str(), widthHint, flags);
+ auto column = std::make_shared<Column>(smartColsColumn);
+
+ columns.push_back(column);
+ return column;
+}
+
+std::shared_ptr<Line> Table::newLine()
+{
+ auto smartColsLine = scols_table_new_line(table, nullptr);
+ auto line = std::make_shared<Line>(smartColsLine);
+
+ lines.push_back(line);
+ return line;
+}
+
+
+std::shared_ptr<Line> Table::newLine(const std::shared_ptr<Line> &parent)
+{
+ auto smartColsLine = scols_table_new_line(table, parent->line);
+ auto line = std::make_shared<Line>(smartColsLine);
+
+ scols_unref_line(smartColsLine);
+ lines.push_back(line);
+ return line;
+}
+
+void Table::addColumn(const std::shared_ptr<Column> &column)
+{
+ scols_table_add_column(table, column->column);
+ columns.push_back(column);
+}
+
+void Table::addLine(const std::shared_ptr<Line> &line)
+{
+ scols_table_add_line(table, line->line);
+ lines.push_back(line);
+}
+
+void Table::removeColumn(const std::shared_ptr<Column> &column)
+{
+ std::remove(std::begin(columns), std::end(columns), column);
+ scols_table_remove_column(table, column->column);
+}
+
+void Table::removeColumns()
+{
+ columns.clear();
+ scols_table_remove_columns(table);
+}
+
+void Table::removeLine(const std::shared_ptr<Line> &line)
+{
+ std::remove(std::begin(lines), std::end(lines), line);
+ scols_table_remove_line(table, line->line);
+}
+
+void Table::removeLines()
+{
+ lines.clear();
+ scols_table_remove_lines(table);
+}
+
+std::string Table::toString()
+{
+ char *data;
+ scols_print_table_to_string(table, &data);
+ return std::string(data);
+}
+
+std::string Table::toString(const std::shared_ptr<Line> &start, const std::shared_ptr<Line> &end)
+{
+ char *data;
+ if (start != nullptr && end != nullptr) {
+ scols_table_print_range_to_string(table, start->line, end->line, &data);
+ auto lines = std::string(data);
+ free(data);
+ return lines;
+ } else {
+ return std::string();
+ }
+}
+
+void Table::setSymbols(struct libscols_symbols *symbols)
+{
+ if (scols_table_set_symbols(table, symbols) == -EINVAL)
+ std::runtime_error("Cannot set stream");
+}
+
+void Table::setDefaultSymbols()
+{
+ if (scols_table_set_default_symbols(table) == -EINVAL)
+ std::runtime_error("Cannot set default symbols");
+}
+
+void Table::setStream(FILE *stream)
+{
+ if (scols_table_set_stream(table, stream) == -EINVAL)
+ std::runtime_error("Cannot set stream");
+}
+
+void Table::setTermforce(TermForce force)
+{
+ if (scols_table_set_termforce(table, static_cast<int>(force)) == -EINVAL)
+ std::runtime_error("Cannot set default symbols");
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_TABLE_HPP
+#define LIBDNF_TABLE_HPP
+
+#include "Cell.hpp"
+#include "Column.hpp"
+#include "Line.hpp"
+
+#include "../tinyformat/tinyformat.hpp"
+
+#include <memory>
+#include <libsmartcols/libsmartcols.h>
+#include <string>
+#include <vector>
+
+class Table
+{
+public:
+ enum class TermForce {
+ AUTO = 0,
+ NEVER,
+ ALWAYS
+ };
+
+ Table();
+ explicit Table(struct libscols_table *table) : table(table) { scols_ref_table(this->table); }
+ Table(const Table &table) { this->table = scols_copy_table(table.table); }
+ ~Table() { scols_unref_table(table); }
+
+ void setName(const std::string &name) { scols_table_set_name(table, name.c_str()); }
+ void setColumnSeparator(const std::string &separator);
+ void setLineSeparator(const std::string &separator) { scols_table_set_line_separator(table, separator.c_str()); }
+ void setSymbols(struct libscols_symbols *symbols);
+ void setDefaultSymbols();
+ void setStream(FILE *stream);
+ void setTermforce(TermForce force);
+ void setTermwidth(size_t width) { scols_table_set_termwidth(table, width); }
+
+ const char *getName() const noexcept { return scols_table_get_name(table); }
+ const char *getColumnSeparator() const { return scols_table_get_column_separator(table); }
+ const char *getLineSeparator() const { return scols_table_get_line_separator(table); }
+ size_t getNumberOfColumns() const noexcept { return scols_table_get_ncols(table); }
+ size_t getNumberOfLines() const noexcept { return scols_table_get_nlines(table); }
+ std::shared_ptr<Cell> getTitle() const { return std::make_shared<Cell>(scols_table_get_title(table)); }
+ std::shared_ptr<Column> getColumn(size_t n) const;
+ std::shared_ptr<Line> getLine(size_t n) const;
+ TermForce getTermforce() const { return static_cast<TermForce>(scols_table_get_termforce(table)); }
+
+ struct libscols_symbols *getSymbols() const { return scols_table_get_symbols(table); }
+ size_t getTermwidth() const { return scols_table_get_termwidth(table); }
+ FILE *getStream() const { return scols_table_get_stream(table); }
+
+ bool isColorsEnabled() const noexcept { return scols_table_colors_wanted(table) == 1; }
+ bool isRaw() const noexcept { return scols_table_is_raw(table) == 1; }
+ bool isAscii() const noexcept { return scols_table_is_ascii(table) == 1; }
+ bool isJson() const noexcept { return scols_table_is_json(table) == 1; }
+ bool isNoheadings() const noexcept { return scols_table_is_noheadings(table) == 1; }
+ bool isEmpty() const noexcept { return scols_table_is_empty(table) == 1; }
+ bool isExport() const noexcept { return scols_table_is_export(table) == 1; }
+ bool isMaxout() const noexcept { return scols_table_is_maxout(table) == 1; }
+ bool isNowrap() const noexcept { return scols_table_is_nowrap(table) == 1; }
+ bool isNoLineSeparator() const noexcept { return scols_table_is_nolinesep(table) == 1; }
+ bool isTree() const noexcept { return scols_table_is_tree(table) == 1; }
+
+ void enableColors(bool enable) { scols_table_enable_colors(table, enable); }
+ void enableRaw(bool enable) { scols_table_enable_raw(table, enable); }
+ void enableAscii(bool enable) { scols_table_enable_ascii(table, enable); }
+ void enableJson(bool enable) { scols_table_enable_json(table, enable); }
+ void enableNoheadings(bool enable) { scols_table_enable_noheadings(table, enable); }
+ void enableExport(bool enable) { scols_table_enable_export(table, enable); }
+ void enableMaxout(bool enable) { scols_table_enable_maxout(table, enable); }
+ void enableNowrap(bool enable) { scols_table_enable_nowrap(table, enable); }
+ void enableNolinesep(bool enable) { scols_table_enable_nolinesep(table, enable); }
+
+ void addColumn(const std::shared_ptr<Column> &column);
+ void removeColumn(const std::shared_ptr<Column> &column);
+ void removeColumns();
+ void moveColumn(const std::shared_ptr<Column> &before, const std::shared_ptr<Column> &toMove);
+ std::shared_ptr<Column> newColumn(const std::string &name, double widthHint = 0, int flags = 0);
+ std::shared_ptr<Column> nextColumn(std::vector<std::shared_ptr<Column>>::iterator &iterator) { return *(iterator++); }
+
+ void addLine(const std::shared_ptr<Line> &line);
+ void removeLine(const std::shared_ptr<Line> &line);
+ void removeLines();
+ std::shared_ptr<Line> newLine();
+ std::shared_ptr<Line> newLine(const std::shared_ptr<Line> &parent);
+ std::shared_ptr<Line> nextLine(std::vector<std::shared_ptr<Line>>::iterator &iterator) { return *(iterator++); }
+
+ void reduceTermwidth(size_t reduce) { scols_table_reduce_termwidth(table, reduce); }
+
+ void sort(const std::shared_ptr<Column> &column) { scols_sort_table(table, column->column); }
+ void sortByTree() { scols_sort_table_by_tree(table); }
+
+ void print() { tinyformat::printf("%s\n", toString()); }
+ void print(const std::shared_ptr<Line> &start, const std::shared_ptr<Line> &end) { tinyformat::printf("%s\n", toString(start, end)); }
+
+ std::string toString();
+ std::string toString(const std::shared_ptr<Line> &start, const std::shared_ptr<Line> &end);
+
+private:
+ struct libscols_table *table;
+
+ std::vector<std::shared_ptr<Line>> lines;
+ std::vector<std::shared_ptr<Column>> columns;
+};
+
+#endif //LIBDNF_TABLE_HPP
--- /dev/null
+set(UTILS_SOURCES
+ ${UTILS_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/Sqlite3.cpp
+ PARENT_SCOPE
+)
--- /dev/null
+/* Sqlite3.cpp
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Sqlite3.hpp"
+
+void
+SQLite3::open()
+{
+ if (db == nullptr) {
+ auto result = sqlite3_open(path.c_str(), &db);
+ if (result != SQLITE_OK) {
+ throw Error(*this, result, "Open failed");
+ }
+
+ // the busy timeout must be set before executing *any* statements
+ // because even setting PRAGMAs can fail with "database is locked" error
+ sqlite3_busy_timeout(db, 10000);
+
+#if SQLITE_VERSION_NUMBER >= 3022000
+ int enabled = 1;
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_PERSIST_WAL, &enabled);
+ if (sqlite3_db_readonly(db, "main") == 1)
+ exec("PRAGMA locking_mode = NORMAL; PRAGMA foreign_keys = ON;");
+ else
+ exec("PRAGMA locking_mode = NORMAL; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON;");
+#else
+ // Journal mode WAL in readonly mode is supported from sqlite version 3.22.0
+ exec("PRAGMA locking_mode = NORMAL; PRAGMA journal_mode = TRUNCATE; PRAGMA foreign_keys = ON;");
+#endif
+ }
+}
+
+void
+SQLite3::close()
+{
+ if (db == nullptr)
+ return;
+ auto result = sqlite3_close(db);
+ if (result == SQLITE_BUSY) {
+ sqlite3_stmt *res;
+ while ((res = sqlite3_next_stmt(db, nullptr))) {
+ sqlite3_finalize(res);
+ }
+ result = sqlite3_close(db);
+ }
+ if (result != SQLITE_OK) {
+ throw Error(*this, result, "Close failed");
+ }
+ db = nullptr;
+}
+
+void
+SQLite3::backup(const std::string &outputFile)
+{
+ sqlite3 *backupDB;
+
+ auto result = sqlite3_open(outputFile.c_str(), &backupDB);
+ if (result != SQLITE_OK) {
+ sqlite3_close(backupDB);
+ throw Error(*this, result, "Failed to open backup database: \"" + outputFile + "\"");
+ }
+
+ sqlite3_backup *backupHandle = sqlite3_backup_init(backupDB, "main", db, "main");
+
+ if (backupHandle) {
+ sqlite3_backup_step(backupHandle, -1);
+ sqlite3_backup_finish(backupHandle);
+ }
+
+ result = sqlite3_errcode(backupDB);
+
+ sqlite3_close(backupDB);
+
+ if (result != SQLITE_OK) {
+ throw Error(*this, result, "Database backup failed");
+ }
+}
+
+void
+SQLite3::restore(const std::string &inputFile)
+{
+ sqlite3 *backupDB;
+
+ auto result = sqlite3_open(inputFile.c_str(), &backupDB);
+ if (result != SQLITE_OK) {
+ sqlite3_close(backupDB);
+ throw Error(*this, result, "Failed to open backup database: \"" + inputFile + "\"");
+ }
+
+ sqlite3_backup *backupHandle = sqlite3_backup_init(db, "main", backupDB, "main");
+
+ if (backupHandle) {
+ sqlite3_backup_step(backupHandle, -1);
+ sqlite3_backup_finish(backupHandle);
+ }
+
+ result = sqlite3_errcode(backupDB);
+
+ sqlite3_close(backupDB);
+
+ if (result != SQLITE_OK) {
+ throw Error(*this, result, "Database restore failed");
+ }
+}
--- /dev/null
+/* Sqlite3.hpp
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SQLITE3_HPP
+#define _SQLITE3_HPP
+
+#include "../../error.hpp"
+#include "../../log.hpp"
+
+#include <sqlite3.h>
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+class SQLite3 {
+public:
+ class Error : public libdnf::Error {
+ public:
+ Error(const SQLite3& s, int code, const std::string &msg) :
+ libdnf::Error("SQLite error on \"" + s.getPath() + "\": " + msg + ": " + s.getError()),
+ ecode{code}
+ {}
+
+ int code() const noexcept { return ecode; }
+ const char *codeStr() const noexcept { return sqlite3_errstr(ecode); }
+
+ protected:
+ int ecode;
+ };
+
+ struct Blob {
+ size_t size;
+ const void *data;
+ };
+
+ class Statement {
+ public:
+ /**
+ * An error class that will log the SQL statement in its constructor.
+ */
+ class Error : public SQLite3::Error {
+ public:
+ Error(Statement& stmt, int code, const std::string& msg) :
+ SQLite3::Error(stmt.db, code, msg)
+ {
+ auto logger(libdnf::Log::getLogger());
+ logger->debug(std::string("SQL statement being executed: ") + stmt.getExpandedSql());
+ }
+ };
+
+ enum class StepResult { DONE, ROW, BUSY };
+
+ Statement(const Statement &) = delete;
+ Statement &operator=(const Statement &) = delete;
+
+ Statement(SQLite3 &db, const char *sql)
+ : db(db)
+ {
+ auto result = sqlite3_prepare_v2(db.db, sql, -1, &stmt, nullptr);
+ if (result != SQLITE_OK)
+ throw SQLite3::Error(db, result, "Creating statement failed");
+ };
+
+ Statement(SQLite3 &db, const std::string &sql)
+ : db(db)
+ {
+ auto result = sqlite3_prepare_v2(db.db, sql.c_str(), sql.length() + 1, &stmt, nullptr);
+ if (result != SQLITE_OK)
+ throw SQLite3::Error(db, result, "Creating statement failed");
+ };
+
+ void bind(int pos, int val)
+ {
+ auto result = sqlite3_bind_int(stmt, pos, val);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Integer bind failed");
+ }
+
+ void bind(int pos, std::int64_t val)
+ {
+ auto result = sqlite3_bind_int64(stmt, pos, val);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Integer64 bind failed");
+ }
+
+ void bind(int pos, std::uint32_t val)
+ {
+ auto result = sqlite3_bind_int(stmt, pos, val);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Unsigned integer bind failed");
+ }
+
+ void bind(int pos, double val)
+ {
+ auto result = sqlite3_bind_double(stmt, pos, val);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Double bind failed");
+ }
+
+ void bind(int pos, bool val)
+ {
+ auto result = sqlite3_bind_int(stmt, pos, val ? 1 : 0);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Bool bind failed");
+ }
+
+ void bind(int pos, const char *val)
+ {
+ auto result = sqlite3_bind_text(stmt, pos, val, -1, SQLITE_TRANSIENT);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Text bind failed");
+ }
+
+ void bind(int pos, const std::string &val)
+ {
+ auto result = sqlite3_bind_text(stmt, pos, val.c_str(), -1, SQLITE_TRANSIENT);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Text bind failed");
+ }
+
+ void bind(int pos, const Blob &val)
+ {
+ auto result = sqlite3_bind_blob(stmt, pos, val.data, val.size, SQLITE_TRANSIENT);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Blob bind failed");
+ }
+
+ void bind(int pos, const std::vector< unsigned char > &val)
+ {
+ auto result = sqlite3_bind_blob(stmt, pos, val.data(), val.size(), SQLITE_TRANSIENT);
+ if (result != SQLITE_OK)
+ throw Error(*this, result, "Blob bind failed");
+ }
+
+ template< typename... Args >
+ Statement &bindv(Args &&... args)
+ {
+ using Pass = int[];
+ size_t pos{0};
+ (void)Pass{(bind(++pos, args), 0)...};
+ return *this;
+ }
+
+ StepResult step()
+ {
+ auto result = sqlite3_step(stmt);
+ switch (result) {
+ case SQLITE_DONE:
+ return StepResult::DONE;
+ case SQLITE_ROW:
+ return StepResult::ROW;
+ case SQLITE_BUSY:
+ return StepResult::BUSY;
+ default:
+ throw Error(*this, result, "Reading a row failed");
+ }
+ }
+
+ int getColumnCount() const { return sqlite3_column_count(stmt); }
+
+ const char *getColumnDatabaseName(int idx) const
+ {
+ return sqlite3_column_database_name(stmt, idx);
+ }
+
+ const char *getColumnTableName(int idx) const
+ {
+ return sqlite3_column_table_name(stmt, idx);
+ }
+
+ const char *getColumnOriginName(int idx) const
+ {
+ return sqlite3_column_origin_name(stmt, idx);
+ }
+
+ const char *getColumnName(int idx) const { return sqlite3_column_name(stmt, idx); }
+
+ const char *getSql() const { return sqlite3_sql(stmt); }
+
+ const char *getExpandedSql()
+ {
+#if SQLITE_VERSION_NUMBER < 3014000
+ // sqlite3_expanded_sql was added in sqlite 3.14; return sql instead
+ return getSql();
+#else
+ expandSql = sqlite3_expanded_sql(stmt);
+ if (!expandSql) {
+ throw libdnf::Exception(
+ "getExpandedSql(): insufficient memory or result "
+ "exceed the maximum SQLite3 string length");
+ }
+ return expandSql;
+#endif
+ }
+
+ void freeExpandedSql() { sqlite3_free(expandSql); }
+
+ /**
+ * Reset prepared query to its initial state, ready to be re-executed.
+ * All the bound values remain untouched - retain their values.
+ * Use clearBindings if you need to reset them as well.
+ */
+ void reset() { sqlite3_reset(stmt); }
+
+ void clearBindings() { sqlite3_clear_bindings(stmt); }
+
+ template< typename T >
+ T get(int idx)
+ {
+ return get(idx, identity< T >{});
+ }
+
+ ~Statement()
+ {
+ freeExpandedSql();
+ sqlite3_finalize(stmt);
+ };
+
+ protected:
+ template< typename T >
+ struct identity {
+ typedef T type;
+ };
+
+ /*template<typename TL>
+ TL get(size_t, identity<TL>)
+ {
+ static_assert(sizeof(TL) == 0, "Not implemented");
+ }*/
+
+ int get(int idx, identity< int >) { return sqlite3_column_int(stmt, idx); }
+
+ uint32_t get(int idx, identity< uint32_t >) { return sqlite3_column_int(stmt, idx); }
+
+ int64_t get(int idx, identity< int64_t >) { return sqlite3_column_int64(stmt, idx); }
+
+ double get(int idx, identity< double >) { return sqlite3_column_double(stmt, idx); }
+
+ bool get(int idx, identity< bool >) { return sqlite3_column_int(stmt, idx) != 0; }
+
+ const char *get(int idx, identity< const char * >)
+ {
+ return reinterpret_cast< const char * >(sqlite3_column_text(stmt, idx));
+ }
+
+ std::string get(int idx, identity< std::string >)
+ {
+ auto ret = reinterpret_cast< const char * >(sqlite3_column_text(stmt, idx));
+ return ret ? ret : "";
+ }
+
+ Blob get(int idx, identity< Blob >)
+ {
+ return {static_cast< size_t >(sqlite3_column_bytes(stmt, idx)),
+ sqlite3_column_blob(stmt, idx)};
+ }
+
+ SQLite3 &db;
+ sqlite3_stmt *stmt;
+ char *expandSql{nullptr};
+ };
+
+ class Query : public Statement {
+ public:
+ Query(SQLite3 &db, const char *sql)
+ : Statement{db, sql}
+ {
+ mapColsName();
+ }
+ Query(SQLite3 &db, const std::string &sql)
+ : Statement{db, sql}
+ {
+ mapColsName();
+ }
+
+ int getColumnIndex(const std::string &colName)
+ {
+ auto it = colsName2idx.find(colName);
+ if (it == colsName2idx.end())
+ throw libdnf::Exception("get() column \"" + colName + "\" not found");
+ return it->second;
+ }
+
+ using Statement::get;
+
+ template< typename T >
+ T get(const std::string &colName)
+ {
+ return get(getColumnIndex(colName), identity< T >{});
+ }
+
+ private:
+ void mapColsName()
+ {
+ for (int idx = 0; idx < getColumnCount(); ++idx) {
+ const char *name = getColumnName(idx);
+ if (name)
+ colsName2idx[name] = idx;
+ }
+ }
+
+ std::map< std::string, int > colsName2idx;
+ };
+
+ SQLite3(const SQLite3 &) = delete;
+ SQLite3 &operator=(const SQLite3 &) = delete;
+
+ SQLite3(const std::string &dbPath)
+ : path{dbPath}
+ , db{nullptr}
+ {
+ open();
+ }
+
+ ~SQLite3() { close(); }
+
+ const std::string &getPath() const { return path; }
+
+ void open();
+ void close();
+ bool isOpened() { return db != nullptr; };
+
+ void exec(const char *sql)
+ {
+ auto result = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
+ if (result != SQLITE_OK) {
+ throw Error(*this, result, "Executing an SQL statement failed");
+ }
+ }
+
+ int changes() { return sqlite3_changes(db); }
+
+ int64_t lastInsertRowID() { return sqlite3_last_insert_rowid(db); }
+
+ std::string getError() const { return sqlite3_errmsg(db); }
+
+ void backup(const std::string &outputFile);
+ void restore(const std::string &inputFile);
+
+protected:
+ std::string path;
+
+ sqlite3 *db;
+};
+
+typedef std::shared_ptr< SQLite3 > SQLite3Ptr;
+
+#endif
--- /dev/null
+# tinyformat.h
+
+## A minimal type safe printf() replacement
+
+**tinyformat.h** is a type safe printf replacement library in a single C++
+header file. If you've ever wanted `printf("%s", s)` to just work regardless
+of the type of `s`, tinyformat might be for you. Design goals include:
+
+* Type safety and extensibility for user defined types.
+* C99 `printf()` compatibility, to the extent possible using `std::ostream`
+* POSIX extension for positional arguments
+* Simplicity and minimalism. A single header file to include and distribute
+ with your projects.
+* Augment rather than replace the standard stream formatting mechanism
+* C++98 support, with optional C++11 niceties
+
+Original project URL:
+https://github.com/c42f/tinyformat
+
--- /dev/null
+// tinyformat.h
+// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
+//
+// Boost Software License - Version 1.0
+//
+// Permission is hereby granted, free of charge, to any person or organization
+// obtaining a copy of the software and accompanying documentation covered by
+// this license (the "Software") to use, reproduce, display, distribute,
+// execute, and transmit the Software, and to prepare derivative works of the
+// Software, and to permit third-parties to whom the Software is furnished to
+// do so, all subject to the following:
+//
+// The copyright notices in the Software and this entire statement, including
+// the above license grant, this restriction and the following disclaimer,
+// must be included in all copies of the Software, in whole or in part, and
+// all derivative works of the Software, unless such copies or derivative
+// works are solely in the form of machine-executable object code generated by
+// a source language processor.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+//------------------------------------------------------------------------------
+// Tinyformat: A minimal type safe printf replacement
+//
+// tinyformat.h is a type safe printf replacement library in a single C++
+// header file. Design goals include:
+//
+// * Type safety and extensibility for user defined types.
+// * C99 printf() compatibility, to the extent possible using std::ostream
+// * POSIX extension for positional arguments
+// * Simplicity and minimalism. A single header file to include and distribute
+// with your projects.
+// * Augment rather than replace the standard stream formatting mechanism
+// * C++98 support, with optional C++11 niceties
+//
+//
+// Main interface example usage
+// ----------------------------
+//
+// To print a date to std::cout for American usage:
+//
+// std::string weekday = "Wednesday";
+// const char* month = "July";
+// size_t day = 27;
+// long hour = 14;
+// int min = 44;
+//
+// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
+//
+// POSIX extension for positional arguments is available.
+// The ability to rearrange formatting arguments is an important feature
+// for localization because the word order may vary in different languages.
+//
+// Previous example for German usage. Arguments are reordered:
+//
+// tfm::printf("%1$s, %3$d. %2$s, %4$d:%5$.2d\n", weekday, month, day, hour, min);
+//
+// The strange types here emphasize the type safety of the interface; it is
+// possible to print a std::string using the "%s" conversion, and a
+// size_t using the "%d" conversion. A similar result could be achieved
+// using either of the tfm::format() functions. One prints on a user provided
+// stream:
+//
+// tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n",
+// weekday, month, day, hour, min);
+//
+// The other returns a std::string:
+//
+// std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
+// weekday, month, day, hour, min);
+// std::cout << date;
+//
+// These are the three primary interface functions. There is also a
+// convenience function printfln() which appends a newline to the usual result
+// of printf() for super simple logging.
+//
+//
+// User defined format functions
+// -----------------------------
+//
+// Simulating variadic templates in C++98 is pretty painful since it requires
+// writing out the same function for each desired number of arguments. To make
+// this bearable tinyformat comes with a set of macros which are used
+// internally to generate the API, but which may also be used in user code.
+//
+// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
+// TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
+// type/name pairs and argument names respectively when called with an integer
+// n between 1 and 16. We can use these to define a macro which generates the
+// desired user defined function with n arguments. To generate all 16 user
+// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an
+// example, see the implementation of printf() at the end of the source file.
+//
+// Sometimes it's useful to be able to pass a list of format arguments through
+// to a non-template function. The FormatList class is provided as a way to do
+// this by storing the argument list in a type-opaque way. Continuing the
+// example from above, we construct a FormatList using makeFormatList():
+//
+// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min);
+//
+// The format list can now be passed into any non-template function and used
+// via a call to the vformat() function:
+//
+// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
+//
+//
+// Additional API information
+// --------------------------
+//
+// Error handling: Define TINYFORMAT_ERROR to customize the error handling for
+// format strings which are unsupported or have the wrong number of format
+// specifiers (calls assert() by default).
+//
+// User defined types: Uses operator<< for user defined types by default.
+// Overload formatValue() for more control.
+
+
+#ifndef TINYFORMAT_H_INCLUDED
+#define TINYFORMAT_H_INCLUDED
+
+namespace tinyformat {}
+//------------------------------------------------------------------------------
+// Config section. Customize to your liking!
+
+// Namespace alias to encourage brevity
+namespace tfm = tinyformat;
+
+// Error handling; calls assert() by default.
+// #define TINYFORMAT_ERROR(reasonString) your_error_handler(reasonString)
+
+// Define for C++11 variadic templates which make the code shorter & more
+// general. If you don't define this, C++11 support is autodetected below.
+// #define TINYFORMAT_USE_VARIADIC_TEMPLATES
+
+
+//------------------------------------------------------------------------------
+// Implementation details.
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+
+#ifndef TINYFORMAT_ASSERT
+# include <cassert>
+# define TINYFORMAT_ASSERT(cond) assert(cond)
+#endif
+
+#ifndef TINYFORMAT_ERROR
+# include <cassert>
+# define TINYFORMAT_ERROR(reason) assert(0 && reason)
+#endif
+
+#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
+# ifdef __GXX_EXPERIMENTAL_CXX0X__
+# define TINYFORMAT_USE_VARIADIC_TEMPLATES
+# endif
+#endif
+
+#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
+// std::showpos is broken on old libstdc++ as provided with macOS. See
+// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
+# define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
+#endif
+
+#ifdef __APPLE__
+// Workaround macOS linker warning: Xcode uses different default symbol
+// visibilities for static libs vs executables (see issue #25)
+# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
+#else
+# define TINYFORMAT_HIDDEN
+#endif
+
+namespace tinyformat {
+
+//------------------------------------------------------------------------------
+namespace detail {
+
+// Test whether type T1 is convertible to type T2
+template <typename T1, typename T2>
+struct is_convertible
+{
+ private:
+ // two types of different size
+ struct fail { char dummy[2]; };
+ struct succeed { char dummy; };
+ // Try to convert a T1 to a T2 by plugging into tryConvert
+ static fail tryConvert(...);
+ static succeed tryConvert(const T2&);
+ static const T1& makeT1();
+ public:
+# ifdef _MSC_VER
+ // Disable spurious loss of precision warnings in tryConvert(makeT1())
+# pragma warning(push)
+# pragma warning(disable:4244)
+# pragma warning(disable:4267)
+# endif
+ // Standard trick: the (...) version of tryConvert will be chosen from
+ // the overload set only if the version taking a T2 doesn't match.
+ // Then we compare the sizes of the return types to check which
+ // function matched. Very neat, in a disgusting kind of way :)
+ static const bool value =
+ sizeof(tryConvert(makeT1())) == sizeof(succeed);
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif
+};
+
+
+// Detect when a type is not a wchar_t string
+template<typename T> struct is_wchar { typedef int tinyformat_wchar_is_not_supported; };
+template<> struct is_wchar<wchar_t*> {};
+template<> struct is_wchar<const wchar_t*> {};
+template<int n> struct is_wchar<const wchar_t[n]> {};
+template<int n> struct is_wchar<wchar_t[n]> {};
+
+
+// Format the value by casting to type fmtT. This default implementation
+// should never be called.
+template<typename T, typename fmtT, bool convertible = is_convertible<T, fmtT>::value>
+struct formatValueAsType
+{
+ static void invoke(std::ostream& /*out*/, const T& /*value*/) { TINYFORMAT_ASSERT(0); }
+};
+// Specialized version for types that can actually be converted to fmtT, as
+// indicated by the "convertible" template parameter.
+template<typename T, typename fmtT>
+struct formatValueAsType<T,fmtT,true>
+{
+ static void invoke(std::ostream& out, const T& value)
+ { out << static_cast<fmtT>(value); }
+};
+
+#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
+template<typename T, bool convertible = is_convertible<T, int>::value>
+struct formatZeroIntegerWorkaround
+{
+ static bool invoke(std::ostream& /**/, const T& /**/) { return false; }
+};
+template<typename T>
+struct formatZeroIntegerWorkaround<T,true>
+{
+ static bool invoke(std::ostream& out, const T& value)
+ {
+ if (static_cast<int>(value) == 0 && out.flags() & std::ios::showpos) {
+ out << "+0";
+ return true;
+ }
+ return false;
+ }
+};
+#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
+
+// Convert an arbitrary type to integer. The version with convertible=false
+// throws an error.
+template<typename T, bool convertible = is_convertible<T,int>::value>
+struct convertToInt
+{
+ static int invoke(const T& /*value*/)
+ {
+ TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
+ "integer for use as variable width or precision");
+ return 0;
+ }
+};
+// Specialization for convertToInt when conversion is possible
+template<typename T>
+struct convertToInt<T,true>
+{
+ static int invoke(const T& value) { return static_cast<int>(value); }
+};
+
+// Format at most ntrunc characters to the given stream.
+template<typename T>
+inline void formatTruncated(std::ostream& out, const T& value, int ntrunc)
+{
+ std::ostringstream tmp;
+ tmp << value;
+ std::string result = tmp.str();
+ out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));
+}
+#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \
+inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \
+{ \
+ std::streamsize len = 0; \
+ while (len < ntrunc && value[len] != 0) \
+ ++len; \
+ out.write(value, len); \
+}
+// Overload for const char* and char*. Could overload for signed & unsigned
+// char too, but these are technically unneeded for printf compatibility.
+TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
+TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
+#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
+
+} // namespace detail
+
+
+//------------------------------------------------------------------------------
+// Variable formatting functions. May be overridden for user-defined types if
+// desired.
+
+
+/// Format a value into a stream, delegating to operator<< by default.
+///
+/// Users may override this for their own types. When this function is called,
+/// the stream flags will have been modified according to the format string.
+/// The format specification is provided in the range [fmtBegin, fmtEnd). For
+/// truncating conversions, ntrunc is set to the desired maximum number of
+/// characters, for example "%.7s" calls formatValue with ntrunc = 7.
+///
+/// By default, formatValue() uses the usual stream insertion operator
+/// operator<< to format the type T, with special cases for the %c and %p
+/// conversions.
+template<typename T>
+inline void formatValue(std::ostream& out, const char* /*fmtBegin*/,
+ const char* fmtEnd, int ntrunc, const T& value)
+{
+#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
+ // Since we don't support printing of wchar_t using "%ls", make it fail at
+ // compile time in preference to printing as a void* at runtime.
+ typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported DummyType;
+ (void) DummyType(); // avoid unused type warning with gcc-4.8
+#endif
+ // The mess here is to support the %c and %p conversions: if these
+ // conversions are active we try to convert the type to a char or const
+ // void* respectively and format that instead of the value itself. For the
+ // %p conversion it's important to avoid dereferencing the pointer, which
+ // could otherwise lead to a crash when printing a dangling (const char*).
+ const bool canConvertToChar = detail::is_convertible<T,char>::value;
+ const bool canConvertToVoidPtr = detail::is_convertible<T, const void*>::value;
+ if (canConvertToChar && *(fmtEnd-1) == 'c')
+ detail::formatValueAsType<T, char>::invoke(out, value);
+ else if (canConvertToVoidPtr && *(fmtEnd-1) == 'p')
+ detail::formatValueAsType<T, const void*>::invoke(out, value);
+#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
+ else if (detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/;
+#endif
+ else if (ntrunc >= 0) {
+ // Take care not to overread C strings in truncating conversions like
+ // "%.4s" where at most 4 characters may be read.
+ detail::formatTruncated(out, value, ntrunc);
+ }
+ else
+ out << value;
+}
+
+
+// Overloaded version for char types to support printing as an integer
+#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \
+inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \
+ const char* fmtEnd, int /**/, charType value) \
+{ \
+ switch (*(fmtEnd-1)) { \
+ case 'u': case 'd': case 'i': case 'o': case 'X': case 'x': \
+ out << static_cast<int>(value); break; \
+ default: \
+ out << value; break; \
+ } \
+}
+// per 3.9.1: char, signed char and unsigned char are all distinct types
+TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
+TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
+TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char)
+#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
+
+
+//------------------------------------------------------------------------------
+// Tools for emulating variadic templates in C++98. The basic idea here is
+// stolen from the boost preprocessor metaprogramming library and cut down to
+// be just general enough for what we need.
+
+#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_ ## n
+#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_ ## n
+#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_ ## n
+#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_ ## n
+
+// To keep it as transparent as possible, the macros below have been generated
+// using python via the excellent cog.py code generation script. This avoids
+// the need for a bunch of complex (but more general) preprocessor tricks as
+// used in boost.preprocessor.
+//
+// To rerun the code generation in place, use `cog.py -r tinyformat.h`
+// (see http://nedbatchelder.com/code/cog). Alternatively you can just create
+// extra versions by hand.
+
+/*[[[cog
+maxParams = 16
+
+def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
+ for j in range(startInd,maxParams+1):
+ list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
+ cog.outl(lineTemplate % {'j':j, 'list':list})
+
+makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
+ 'class T%(i)d')
+
+cog.outl()
+makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
+ 'const T%(i)d& v%(i)d')
+
+cog.outl()
+makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
+
+cog.outl()
+cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
+makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
+ 'v%(i)d', startInd = 2)
+
+cog.outl()
+cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' +
+ ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
+]]]*/
+#define TINYFORMAT_ARGTYPES_1 class T1
+#define TINYFORMAT_ARGTYPES_2 class T1, class T2
+#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
+#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
+#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
+#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6
+#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7
+#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8
+#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9
+#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10
+#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11
+#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12
+#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13
+#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14
+#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15
+#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16
+
+#define TINYFORMAT_VARARGS_1 const T1& v1
+#define TINYFORMAT_VARARGS_2 const T1& v1, const T2& v2
+#define TINYFORMAT_VARARGS_3 const T1& v1, const T2& v2, const T3& v3
+#define TINYFORMAT_VARARGS_4 const T1& v1, const T2& v2, const T3& v3, const T4& v4
+#define TINYFORMAT_VARARGS_5 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5
+#define TINYFORMAT_VARARGS_6 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6
+#define TINYFORMAT_VARARGS_7 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7
+#define TINYFORMAT_VARARGS_8 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8
+#define TINYFORMAT_VARARGS_9 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9
+#define TINYFORMAT_VARARGS_10 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10
+#define TINYFORMAT_VARARGS_11 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11
+#define TINYFORMAT_VARARGS_12 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12
+#define TINYFORMAT_VARARGS_13 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13
+#define TINYFORMAT_VARARGS_14 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14
+#define TINYFORMAT_VARARGS_15 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15
+#define TINYFORMAT_VARARGS_16 const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9, const T10& v10, const T11& v11, const T12& v12, const T13& v13, const T14& v14, const T15& v15, const T16& v16
+
+#define TINYFORMAT_PASSARGS_1 v1
+#define TINYFORMAT_PASSARGS_2 v1, v2
+#define TINYFORMAT_PASSARGS_3 v1, v2, v3
+#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
+#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
+#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
+#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
+#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
+#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
+#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
+#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
+#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
+#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
+#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
+#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
+#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
+
+#define TINYFORMAT_PASSARGS_TAIL_1
+#define TINYFORMAT_PASSARGS_TAIL_2 , v2
+#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
+#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
+#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
+#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
+#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
+#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
+#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
+#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
+#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
+#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
+#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
+#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
+#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
+#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
+
+#define TINYFORMAT_FOREACH_ARGNUM(m) \
+ m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16)
+//[[[end]]]
+
+
+
+namespace detail {
+
+// Type-opaque holder for an argument to format(), with associated actions on
+// the type held as explicit function pointers. This allows FormatArg's for
+// each argument to be allocated as a homogeneous array inside FormatList
+// whereas a naive implementation based on inheritance does not.
+class FormatArg
+{
+ public:
+ FormatArg()
+ : m_value(NULL),
+ m_formatImpl(NULL),
+ m_toIntImpl(NULL)
+ { }
+
+ template<typename T>
+ FormatArg(const T& value)
+ : m_value(static_cast<const void*>(&value)),
+ m_formatImpl(&formatImpl<T>),
+ m_toIntImpl(&toIntImpl<T>)
+ { }
+
+ void format(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc) const
+ {
+ TINYFORMAT_ASSERT(m_value);
+ TINYFORMAT_ASSERT(m_formatImpl);
+ m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
+ }
+
+ int toInt() const
+ {
+ TINYFORMAT_ASSERT(m_value);
+ TINYFORMAT_ASSERT(m_toIntImpl);
+ return m_toIntImpl(m_value);
+ }
+
+ private:
+ template<typename T>
+ TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc, const void* value)
+ {
+ formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast<const T*>(value));
+ }
+
+ template<typename T>
+ TINYFORMAT_HIDDEN static int toIntImpl(const void* value)
+ {
+ return convertToInt<T>::invoke(*static_cast<const T*>(value));
+ }
+
+ const void* m_value;
+ void (*m_formatImpl)(std::ostream& out, const char* fmtBegin,
+ const char* fmtEnd, int ntrunc, const void* value);
+ int (*m_toIntImpl)(const void* value);
+};
+
+
+// Parse and return an integer from the string c, as atoi()
+// On return, c is set to one past the end of the integer.
+inline int parseIntAndAdvance(const char*& c)
+{
+ int i = 0;
+ for (;*c >= '0' && *c <= '9'; ++c)
+ i = 10*i + (*c - '0');
+ return i;
+}
+
+// Parse width or precision `n` from format string pointer `c`, and advance it
+// to the next character. If an indirection is requested with `*`, the argument
+// is read from `args[argIndex]` and `argIndex` is incremented (or read
+// from `args[n]` in positional mode). Returns true if one or more
+// characters were read.
+inline bool parseWidthOrPrecision(int& n, const char*& c, bool positionalMode,
+ const detail::FormatArg* args,
+ int& argIndex, int numArgs)
+{
+ if (*c >= '0' && *c <= '9') {
+ n = parseIntAndAdvance(c);
+ }
+ else if (*c == '*') {
+ ++c;
+ n = 0;
+ if (positionalMode) {
+ int pos = parseIntAndAdvance(c) - 1;
+ if (*c != '$')
+ TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
+ if (pos >= 0 && pos < numArgs)
+ n = args[pos].toInt();
+ else
+ TINYFORMAT_ERROR("tinyformat: Positional argument out of range");
+ ++c;
+ }
+ else {
+ if (argIndex < numArgs)
+ n = args[argIndex++].toInt();
+ else
+ TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width or precision");
+ }
+ }
+ else {
+ return false;
+ }
+ return true;
+}
+
+// Print literal part of format string and return next format spec position.
+//
+// Skips over any occurrences of '%%', printing a literal '%' to the output.
+// The position of the first % character of the next nontrivial format spec is
+// returned, or the end of string.
+inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt)
+{
+ const char* c = fmt;
+ for (;; ++c) {
+ if (*c == '\0') {
+ out.write(fmt, c - fmt);
+ return c;
+ }
+ else if (*c == '%') {
+ out.write(fmt, c - fmt);
+ if (*(c+1) != '%')
+ return c;
+ // for "%%", tack trailing % onto next literal section.
+ fmt = ++c;
+ }
+ }
+}
+
+
+// Parse a format string and set the stream state accordingly.
+//
+// The format mini-language recognized here is meant to be the one from C99,
+// with the form "%[flags][width][.precision][length]type" with POSIX
+// positional arguments extension.
+//
+// POSIX positional arguments extension:
+// Conversions can be applied to the nth argument after the format in
+// the argument list, rather than to the next unused argument. In this case,
+// the conversion specifier character % (see below) is replaced by the sequence
+// "%n$", where n is a decimal integer in the range [1,{NL_ARGMAX}],
+// giving the position of the argument in the argument list. This feature
+// provides for the definition of format strings that select arguments
+// in an order appropriate to specific languages.
+//
+// The format can contain either numbered argument conversion specifications
+// (that is, "%n$" and "*m$"), or unnumbered argument conversion specifications
+// (that is, % and * ), but not both. The only exception to this is that %%
+// can be mixed with the "%n$" form. The results of mixing numbered and
+// unnumbered argument specifications in a format string are undefined.
+// When numbered argument specifications are used, specifying the Nth argument
+// requires that all the leading arguments, from the first to the (N-1)th,
+// are specified in the format string.
+//
+// In format strings containing the "%n$" form of conversion specification,
+// numbered arguments in the argument list can be referenced from the format
+// string as many times as required.
+//
+// Formatting options which can't be natively represented using the ostream
+// state are returned in spacePadPositive (for space padded positive numbers)
+// and ntrunc (for truncating conversions). argIndex is incremented if
+// necessary to pull out variable width and precision. The function returns a
+// pointer to the character after the end of the current format spec.
+inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode,
+ bool& spacePadPositive,
+ int& ntrunc, const char* fmtStart,
+ const detail::FormatArg* args,
+ int& argIndex, int numArgs)
+{
+ TINYFORMAT_ASSERT(*fmtStart == '%');
+ // Reset stream state to defaults.
+ out.width(0);
+ out.precision(6);
+ out.fill(' ');
+ // Reset most flags; ignore irrelevant unitbuf & skipws.
+ out.unsetf(std::ios::adjustfield | std::ios::basefield |
+ std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
+ std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
+ bool precisionSet = false;
+ bool widthSet = false;
+ int widthExtra = 0;
+ const char* c = fmtStart + 1;
+
+ // 1) Parse an argument index (if followed by '$') or a width possibly
+ // preceded with '0' flag.
+ if (*c >= '0' && *c <= '9') {
+ const char tmpc = *c;
+ int value = parseIntAndAdvance(c);
+ if (*c == '$') {
+ // value is an argument index
+ if (value > 0 && value <= numArgs)
+ argIndex = value - 1;
+ else
+ TINYFORMAT_ERROR("tinyformat: Positional argument out of range");
+ ++c;
+ positionalMode = true;
+ }
+ else if (positionalMode) {
+ TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
+ }
+ else {
+ if (tmpc == '0') {
+ // Use internal padding so that numeric values are
+ // formatted correctly, eg -00010 rather than 000-10
+ out.fill('0');
+ out.setf(std::ios::internal, std::ios::adjustfield);
+ }
+ if (value != 0) {
+ // Nonzero value means that we parsed width.
+ widthSet = true;
+ out.width(value);
+ }
+ }
+ }
+ else if (positionalMode) {
+ TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
+ }
+ // 2) Parse flags and width if we did not do it in previous step.
+ if (!widthSet) {
+ // Parse flags
+ for (;; ++c) {
+ switch (*c) {
+ case '#':
+ out.setf(std::ios::showpoint | std::ios::showbase);
+ continue;
+ case '0':
+ // overridden by left alignment ('-' flag)
+ if (!(out.flags() & std::ios::left)) {
+ // Use internal padding so that numeric values are
+ // formatted correctly, eg -00010 rather than 000-10
+ out.fill('0');
+ out.setf(std::ios::internal, std::ios::adjustfield);
+ }
+ continue;
+ case '-':
+ out.fill(' ');
+ out.setf(std::ios::left, std::ios::adjustfield);
+ continue;
+ case ' ':
+ // overridden by show positive sign, '+' flag.
+ if (!(out.flags() & std::ios::showpos))
+ spacePadPositive = true;
+ continue;
+ case '+':
+ out.setf(std::ios::showpos);
+ spacePadPositive = false;
+ widthExtra = 1;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ // Parse width
+ int width = 0;
+ widthSet = parseWidthOrPrecision(width, c, positionalMode,
+ args, argIndex, numArgs);
+ if (widthSet) {
+ if (width < 0) {
+ // negative widths correspond to '-' flag set
+ out.fill(' ');
+ out.setf(std::ios::left, std::ios::adjustfield);
+ width = -width;
+ }
+ out.width(width);
+ }
+ }
+ // 3) Parse precision
+ if (*c == '.') {
+ ++c;
+ int precision = 0;
+ parseWidthOrPrecision(precision, c, positionalMode,
+ args, argIndex, numArgs);
+ // Presence of `.` indicates precision set, unless the inferred value
+ // was negative in which case the default is used.
+ precisionSet = precision >= 0;
+ if (precisionSet)
+ out.precision(precision);
+ }
+ // 4) Ignore any C99 length modifier
+ while (*c == 'l' || *c == 'h' || *c == 'L' ||
+ *c == 'j' || *c == 'z' || *c == 't') {
+ ++c;
+ }
+ // 5) We're up to the conversion specifier character.
+ // Set stream flags based on conversion specifier (thanks to the
+ // boost::format class for forging the way here).
+ bool intConversion = false;
+ switch (*c) {
+ case 'u': case 'd': case 'i':
+ out.setf(std::ios::dec, std::ios::basefield);
+ intConversion = true;
+ break;
+ case 'o':
+ out.setf(std::ios::oct, std::ios::basefield);
+ intConversion = true;
+ break;
+ case 'X':
+ out.setf(std::ios::uppercase);
+ // Falls through
+ case 'x': case 'p':
+ out.setf(std::ios::hex, std::ios::basefield);
+ intConversion = true;
+ break;
+ case 'E':
+ out.setf(std::ios::uppercase);
+ // Falls through
+ case 'e':
+ out.setf(std::ios::scientific, std::ios::floatfield);
+ out.setf(std::ios::dec, std::ios::basefield);
+ break;
+ case 'F':
+ out.setf(std::ios::uppercase);
+ // Falls through
+ case 'f':
+ out.setf(std::ios::fixed, std::ios::floatfield);
+ break;
+ case 'A':
+ out.setf(std::ios::uppercase);
+ // Falls through
+ case 'a':
+# ifdef _MSC_VER
+ // Workaround https://developercommunity.visualstudio.com/content/problem/520472/hexfloat-stream-output-does-not-ignore-precision-a.html
+ // by always setting maximum precision on MSVC to avoid precision
+ // loss for doubles.
+ out.precision(13);
+# endif
+ out.setf(std::ios::fixed | std::ios::scientific, std::ios::floatfield);
+ break;
+ case 'G':
+ out.setf(std::ios::uppercase);
+ // Falls through
+ case 'g':
+ out.setf(std::ios::dec, std::ios::basefield);
+ // As in boost::format, let stream decide float format.
+ out.flags(out.flags() & ~std::ios::floatfield);
+ break;
+ case 'c':
+ // Handled as special case inside formatValue()
+ break;
+ case 's':
+ if (precisionSet)
+ ntrunc = static_cast<int>(out.precision());
+ // Make %s print Booleans as "true" and "false"
+ out.setf(std::ios::boolalpha);
+ break;
+ case 'n':
+ // Not supported - will cause problems!
+ TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported");
+ break;
+ case '\0':
+ TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
+ "terminated by end of string");
+ return c;
+ default:
+ break;
+ }
+ if (intConversion && precisionSet && !widthSet) {
+ // "precision" for integers gives the minimum number of digits (to be
+ // padded with zeros on the left). This isn't really supported by the
+ // iostreams, but we can approximately simulate it with the width if
+ // the width isn't otherwise used.
+ out.width(out.precision() + widthExtra);
+ out.setf(std::ios::internal, std::ios::adjustfield);
+ out.fill('0');
+ }
+ return c+1;
+}
+
+
+//------------------------------------------------------------------------------
+inline void formatImpl(std::ostream& out, const char* fmt,
+ const detail::FormatArg* args,
+ int numArgs)
+{
+ // Saved stream state
+ std::streamsize origWidth = out.width();
+ std::streamsize origPrecision = out.precision();
+ std::ios::fmtflags origFlags = out.flags();
+ char origFill = out.fill();
+
+ // "Positional mode" means all format specs should be of the form "%n$..."
+ // with `n` an integer. We detect this in `streamStateFromFormat`.
+ bool positionalMode = false;
+ int argIndex = 0;
+ while (true) {
+ fmt = printFormatStringLiteral(out, fmt);
+ if (*fmt == '\0') {
+ if (!positionalMode && argIndex < numArgs) {
+ TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string");
+ }
+ break;
+ }
+ bool spacePadPositive = false;
+ int ntrunc = -1;
+ const char* fmtEnd = streamStateFromFormat(out, positionalMode, spacePadPositive, ntrunc, fmt,
+ args, argIndex, numArgs);
+ // NB: argIndex may be incremented by reading variable width/precision
+ // in `streamStateFromFormat`, so do the bounds check here.
+ if (argIndex >= numArgs) {
+ TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
+ return;
+ }
+ const FormatArg& arg = args[argIndex];
+ // Format the arg into the stream.
+ if (!spacePadPositive) {
+ arg.format(out, fmt, fmtEnd, ntrunc);
+ }
+ else {
+ // The following is a special case with no direct correspondence
+ // between stream formatting and the printf() behaviour. Simulate
+ // it crudely by formatting into a temporary string stream and
+ // munging the resulting string.
+ std::ostringstream tmpStream;
+ tmpStream.copyfmt(out);
+ tmpStream.setf(std::ios::showpos);
+ arg.format(tmpStream, fmt, fmtEnd, ntrunc);
+ std::string result = tmpStream.str(); // allocates... yuck.
+ for (size_t i = 0, iend = result.size(); i < iend; ++i) {
+ if (result[i] == '+')
+ result[i] = ' ';
+ }
+ out << result;
+ }
+ if (!positionalMode)
+ ++argIndex;
+ fmt = fmtEnd;
+ }
+
+ // Restore stream state
+ out.width(origWidth);
+ out.precision(origPrecision);
+ out.flags(origFlags);
+ out.fill(origFill);
+}
+
+} // namespace detail
+
+
+/// List of template arguments format(), held in a type-opaque way.
+///
+/// A const reference to FormatList (typedef'd as FormatListRef) may be
+/// conveniently used to pass arguments to non-template functions: All type
+/// information has been stripped from the arguments, leaving just enough of a
+/// common interface to perform formatting as required.
+class FormatList
+{
+ public:
+ FormatList(detail::FormatArg* args, int N)
+ : m_args(args), m_N(N) { }
+
+ friend void vformat(std::ostream& out, const char* fmt,
+ const FormatList& list);
+
+ private:
+ const detail::FormatArg* m_args;
+ int m_N;
+};
+
+/// Reference to type-opaque format list for passing to vformat()
+typedef const FormatList& FormatListRef;
+
+
+namespace detail {
+
+// Format list subclass with fixed storage to avoid dynamic allocation
+template<int N>
+class FormatListN : public FormatList
+{
+ public:
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+ template<typename... Args>
+ FormatListN(const Args&... args)
+ : FormatList(&m_formatterStore[0], N),
+ m_formatterStore { FormatArg(args)... }
+ { static_assert(sizeof...(args) == N, "Number of args must be N"); }
+#else // C++98 version
+ void init(int) {}
+# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
+ \
+ template<TINYFORMAT_ARGTYPES(n)> \
+ FormatListN(TINYFORMAT_VARARGS(n)) \
+ : FormatList(&m_formatterStore[0], n) \
+ { TINYFORMAT_ASSERT(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
+ \
+ template<TINYFORMAT_ARGTYPES(n)> \
+ void init(int i, TINYFORMAT_VARARGS(n)) \
+ { \
+ m_formatterStore[i] = FormatArg(v1); \
+ init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \
+ }
+
+ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
+# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
+#endif
+ FormatListN(const FormatListN& other)
+ : FormatList(&m_formatterStore[0], N)
+ { std::copy(&other.m_formatterStore[0], &other.m_formatterStore[N],
+ &m_formatterStore[0]); }
+
+ private:
+ FormatArg m_formatterStore[N];
+};
+
+// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard
+template<> class FormatListN<0> : public FormatList
+{
+ public: FormatListN() : FormatList(0, 0) {}
+};
+
+} // namespace detail
+
+
+//------------------------------------------------------------------------------
+// Primary API functions
+
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+
+/// Make type-agnostic format list from list of template arguments.
+///
+/// The exact return type of this function is an implementation detail and
+/// shouldn't be relied upon. Instead it should be stored as a FormatListRef:
+///
+/// FormatListRef formatList = makeFormatList( /*...*/ );
+template<typename... Args>
+detail::FormatListN<sizeof...(Args)> makeFormatList(const Args&... args)
+{
+ return detail::FormatListN<sizeof...(args)>(args...);
+}
+
+#else // C++98 version
+
+inline detail::FormatListN<0> makeFormatList()
+{
+ return detail::FormatListN<0>();
+}
+#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \
+template<TINYFORMAT_ARGTYPES(n)> \
+detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) \
+{ \
+ return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n)); \
+}
+TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
+#undef TINYFORMAT_MAKE_MAKEFORMATLIST
+
+#endif
+
+/// Format list of arguments to the stream according to the given format string.
+///
+/// The name vformat() is chosen for the semantic similarity to vprintf(): the
+/// list of format arguments is held in a single function argument.
+inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)
+{
+ detail::formatImpl(out, fmt, list.m_args, list.m_N);
+}
+
+
+#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
+
+/// Format list of arguments to the stream according to given format string.
+template<typename... Args>
+void format(std::ostream& out, const char* fmt, const Args&... args)
+{
+ vformat(out, fmt, makeFormatList(args...));
+}
+
+/// Format list of arguments according to the given format string and return
+/// the result as a string.
+template<typename... Args>
+std::string format(const char* fmt, const Args&... args)
+{
+ std::ostringstream oss;
+ format(oss, fmt, args...);
+ return oss.str();
+}
+
+/// Format list of arguments to std::cout, according to the given format string
+template<typename... Args>
+void printf(const char* fmt, const Args&... args)
+{
+ format(std::cout, fmt, args...);
+}
+
+template<typename... Args>
+void printfln(const char* fmt, const Args&... args)
+{
+ format(std::cout, fmt, args...);
+ std::cout << '\n';
+}
+
+
+#else // C++98 version
+
+inline void format(std::ostream& out, const char* fmt)
+{
+ vformat(out, fmt, makeFormatList());
+}
+
+inline std::string format(const char* fmt)
+{
+ std::ostringstream oss;
+ format(oss, fmt);
+ return oss.str();
+}
+
+inline void printf(const char* fmt)
+{
+ format(std::cout, fmt);
+}
+
+inline void printfln(const char* fmt)
+{
+ format(std::cout, fmt);
+ std::cout << '\n';
+}
+
+#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \
+ \
+template<TINYFORMAT_ARGTYPES(n)> \
+void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \
+{ \
+ vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \
+} \
+ \
+template<TINYFORMAT_ARGTYPES(n)> \
+std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \
+{ \
+ std::ostringstream oss; \
+ format(oss, fmt, TINYFORMAT_PASSARGS(n)); \
+ return oss.str(); \
+} \
+ \
+template<TINYFORMAT_ARGTYPES(n)> \
+void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \
+{ \
+ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
+} \
+ \
+template<TINYFORMAT_ARGTYPES(n)> \
+void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \
+{ \
+ format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \
+ std::cout << '\n'; \
+}
+
+TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
+#undef TINYFORMAT_MAKE_FORMAT_FUNCS
+
+#endif
+
+
+} // namespace tinyformat
+
+#endif // TINYFORMAT_H_INCLUDED
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "url-encode.hpp"
+
+
+namespace libdnf {
+
+std::string urlEncode(const std::string & src, const std::string & exclude) {
+ auto noEncode = [&exclude](char ch)
+ {
+ if (isalnum(ch) || ch=='-' || ch == '.' || ch == '_' || ch == '~') {
+ return true;
+ }
+
+ if (exclude.find(ch) != std::string::npos) {
+ return true;
+ }
+
+ return false;
+ };
+
+ // compute length of encoded string
+ auto len = src.length();
+ for (auto ch : src) {
+ if (!noEncode(ch))
+ len += 2;
+ }
+
+ // encode the input string
+ std::string encoded;
+ encoded.reserve(len);
+ for (auto ch : src) {
+ if (noEncode(ch))
+ encoded.push_back(ch);
+ else {
+ encoded.push_back('%');
+ unsigned char hex;
+ hex = static_cast<unsigned char>(ch) >> 4;
+ hex += hex <= 9 ? '0' : 'a' - 10;
+ encoded.push_back(hex);
+ hex = static_cast<unsigned char>(ch) & 0x0F;
+ hex += hex <= 9 ? '0' : 'a' - 10;
+ encoded.push_back(hex);
+ }
+ }
+
+ return encoded;
+}
+
+std::string urlDecode(const std::string & src) {
+ std::string out;
+
+ for (size_t i = 0; i < src.length(); ++i) {
+ char ch = src[i];
+
+ if (ch == '%') {
+ out.push_back(stoi(src.substr(i + 1, 2), nullptr, 16));
+ i += 2;
+ } else {
+ out.push_back(ch);
+ }
+ }
+
+ return out;
+}
+
+} // namespace libdnf
--- /dev/null
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_UTILS_URLENCODE_HPP
+#define LIBDNF_UTILS_URLENCODE_HPP
+
+#include <string>
+
+
+namespace libdnf {
+
+/**
+* @brief Converts the given input string to a URL encoded string
+*
+* All input characters that are not a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted
+* to their "URL escaped" version (%NN where NN is a two-digit hexadecimal number).
+*
+* @param src String to encode
+* @param exclude A list of characters that won't be encoded
+* @return URL encoded string
+*/
+std::string urlEncode(const std::string & src, const std::string & exclude = "");
+
+/**
+* @brief URL-decodes the input string
+*
+* All percent signs followed by two hex digits are decoded to the characters
+* they represent.
+*
+* @param src The string to decode
+* @return URL-decoded string
+*/
+std::string urlDecode(const std::string & src);
+
+} // namespace libdnf
+
+#endif
--- /dev/null
+#include "utils.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/sack/advisorymodule.hpp"
+#include <librepo/librepo.h>
+
+#include <tinyformat/tinyformat.hpp>
+
+#include <algorithm>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <cstring>
+#include <stdexcept>
+
+extern "C" {
+#include <solv/solv_xfopen.h>
+};
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <random>
+
+namespace libdnf {
+
+bool isAdvisoryApplicable(libdnf::Advisory & advisory, DnfSack * sack)
+{
+ for (auto & advisoryModule: advisory.getModules()) {
+ if (advisoryModule.isApplicable()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace string {
+
+std::vector<std::string> split(const std::string &source, const char *delimiter, int maxSplit)
+{
+ if (source.empty())
+ throw std::runtime_error{"Source cannot be empty"};
+
+ std::string::size_type tokenBeginIndex = 0;
+ std::vector<std::string> container;
+
+ while ((tokenBeginIndex = source.find_first_not_of(delimiter, tokenBeginIndex)) != source.npos) {
+ if (maxSplit != -1 && ((int) (container.size() + 1 )) == maxSplit) {
+ container.emplace_back(source.substr(tokenBeginIndex));
+ break;
+ }
+
+ auto tokenEndIndex = source.find_first_of(delimiter, tokenBeginIndex);
+ container.emplace_back(source.substr(tokenBeginIndex, tokenEndIndex - tokenBeginIndex));
+ tokenBeginIndex = tokenEndIndex;
+ }
+
+ if (container.empty()) {
+ throw std::runtime_error{"No delimiter found in source: " + source};
+ }
+
+ return container;
+}
+
+std::vector<std::string> rsplit(const std::string &source, const char *delimiter, int maxSplit)
+{
+ if (source.empty())
+ throw std::runtime_error{"Source cannot be empty"};
+
+ std::string sequence = source;
+ std::string::size_type tokenBeginIndex = 0;
+ std::vector<std::string> container;
+
+ while ((tokenBeginIndex = sequence.find_last_of(delimiter)) != sequence.npos) {
+ if (maxSplit != -1 && ((int) (container.size() + 1 )) == maxSplit) {
+ container.emplace_back(source.substr(0, tokenBeginIndex));
+ break;
+ }
+
+ container.emplace(container.begin(), source.substr(tokenBeginIndex + 1));
+ sequence = sequence.substr(0, tokenBeginIndex);
+ }
+
+ if (container.empty()) {
+ throw std::runtime_error{"No delimiter found in source: " + source};
+ }
+
+ return container;
+}
+
+std::string trimSuffix(const std::string &source, const std::string &suffix)
+{
+ if (source.length() < suffix.length())
+ throw std::runtime_error{"Suffix cannot be longer than source"};
+
+ if (endsWith(source, suffix))
+ return source.substr(0, source.length() - suffix.length());
+
+ throw std::runtime_error{"Suffix '" + suffix + "' not found"};
+}
+
+std::string trimPrefix(const std::string &source, const std::string &prefix)
+{
+ if (source.length() < prefix.length())
+ throw std::runtime_error{"Prefix cannot be longer than source"};
+
+ if (startsWith(source, prefix))
+ return source.substr(prefix.length() - 1);
+
+ throw std::runtime_error{"Prefix '" + prefix + "' not found"};
+}
+
+std::string trim(const std::string &source)
+{
+ size_t first = source.find_first_not_of(" \t");
+ if (first == source.npos) return "";
+ size_t last = source.find_last_not_of(" \t");
+ return source.substr(first, (last - first + 1));
+}
+
+bool startsWith(const std::string & source, const std::string & toMatch)
+{
+ return source.compare(0, toMatch.size(), toMatch) == 0;
+}
+
+bool endsWith(const std::string & source, const std::string & toMatch)
+{
+ auto toMatchSize = toMatch.size();
+ return source.size() >= toMatchSize && source.compare(
+ source.size() - toMatchSize, toMatchSize, toMatch) == 0;
+}
+
+}
+
+bool haveFilesSameContent(const char * filePath1, const char * filePath2)
+{
+ static constexpr int BLOCK_SIZE = 4096;
+ bool ret = false;
+ int fd1 = -1;
+ int fd2 = -1;
+ do {
+ if ((fd1 = open(filePath1, 0)) == -1)
+ break;
+ if ((fd2 = open(filePath2, 0)) == -1)
+ break;
+ auto len1 = lseek(fd1, 0, SEEK_END);
+ auto len2 = lseek(fd2, 0, SEEK_END);
+ if (len1 != len2)
+ break;
+ ret = true;
+ if (len1 == 0)
+ break;
+ lseek(fd1, 0, SEEK_SET);
+ lseek(fd2, 0, SEEK_SET);
+ char buf1[BLOCK_SIZE], buf2[BLOCK_SIZE];
+ ssize_t readed;
+ do {
+ readed = read(fd1, buf1, BLOCK_SIZE);
+ auto readed2 = read(fd2, buf2, BLOCK_SIZE);
+ if (readed2 != readed || memcmp(buf1, buf2, readed) != 0) {
+ ret = false;
+ break;
+ }
+ } while (readed == BLOCK_SIZE);
+ } while (false);
+
+ if (fd1 != -1)
+ close(fd1);
+ if (fd2 != -1)
+ close(fd2);
+ return ret;
+}
+
+static bool
+saveFile(const char * filePath, const char * newFileContent, unsigned long newFileContentLen)
+{
+ int fd = -1;
+ if ((fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
+ return false;
+ auto writtenSize = write(fd, newFileContent, newFileContentLen);
+ close(fd);
+ return (static_cast<unsigned long>(writtenSize) == newFileContentLen);
+}
+
+bool updateFile(const char * filePath, const char * newFileContent)
+{
+ static constexpr int BLOCK_SIZE = 4096;
+ int fd = -1;
+ const char * tmpFileContent = newFileContent;
+ auto newFileContentLen = strlen(newFileContent);
+
+ if ((fd = open(filePath, O_RDONLY)) == -1)
+ return saveFile(filePath, newFileContent, newFileContentLen);
+ auto len = lseek(fd, 0, SEEK_END);
+ if (len < 0 || (unsigned long)len != newFileContentLen) {
+ close(fd);
+ return saveFile(filePath, newFileContent, newFileContentLen);
+ }
+ // No need to update file when newFileContentLen and len of file == 0
+ if (newFileContentLen > 0) {
+ lseek(fd, 0, SEEK_SET);
+ char buf1[BLOCK_SIZE];
+ ssize_t readed;
+ do {
+ readed = read(fd, buf1, BLOCK_SIZE);
+ if (readed < 0 && errno == EINTR)
+ continue;
+ if (readed < 0 || memcmp(buf1, tmpFileContent, readed) != 0) {
+ close(fd);
+ return saveFile(filePath, newFileContent, newFileContentLen);
+ }
+ tmpFileContent = tmpFileContent + BLOCK_SIZE;
+ } while (readed == BLOCK_SIZE);
+ }
+
+ if (fd != -1)
+ close(fd);
+ return true;
+}
+
+namespace filesystem {
+
+bool exists(const std::string &name)
+{
+ struct stat buffer;
+ return stat(name.c_str(), &buffer) == 0;
+}
+
+bool isDIR(const std::string& dirPath)
+{
+ struct stat buf;
+ lstat(dirPath.c_str(), &buf);
+ return S_ISDIR(buf.st_mode);
+}
+
+
+std::vector<std::string> getDirContent(const std::string &dirPath)
+{
+ std::vector<std::string> content{};
+ struct dirent *ent;
+ DIR *dir = opendir(dirPath.c_str());
+
+ if (dir != nullptr) {
+ while ((ent = readdir(dir)) != nullptr) {
+ if (strcmp(ent->d_name, "..") == 0 ||
+ strcmp(ent->d_name, ".") == 0 )
+ continue;
+
+ auto fullPath = dirPath;
+ if (!string::endsWith(fullPath, "/"))
+ fullPath += "/";
+ fullPath += ent->d_name;
+
+ content.emplace_back(fullPath);
+ }
+ closedir (dir);
+ }
+
+ return content;
+}
+
+void decompress(const char * inPath, const char * outPath, mode_t outMode, const char * compressType)
+{
+ auto inFd = open(inPath, O_RDONLY);
+ if (inFd == -1)
+ throw std::runtime_error(tfm::format("Error opening %s: %s", inPath, strerror(errno)));
+ if (!compressType)
+ compressType = inPath;
+ auto inFile = solv_xfopen_fd(compressType, inFd, "r");
+ if (inFile == NULL) {
+ close(inFd);
+ throw std::runtime_error(tfm::format("solv_xfopen_fd: Can't open stream for %s", inPath));
+ }
+ auto outFd = open(outPath, O_WRONLY | O_CREAT | O_TRUNC, outMode);
+ if (outFd == -1) {
+ int err = errno;
+ fclose(inFile);
+ throw std::runtime_error(tfm::format("Error opening %s: %s", outPath, strerror(err)));
+ }
+ char buf[4096];
+ while (auto readBytes = fread(buf, 1, sizeof(buf), inFile)) {
+ auto writtenBytes = write(outFd, buf, readBytes);
+ if (writtenBytes == -1) {
+ int err = errno;
+ close(outFd);
+ fclose(inFile);
+ throw std::runtime_error(tfm::format("Error writing to %s: %s", outPath, strerror(err)));
+ }
+ if (writtenBytes != static_cast<int>(readBytes)) {
+ close(outFd);
+ fclose(inFile);
+ throw std::runtime_error(tfm::format("Unknown error while writing to %s", outPath));
+ }
+ }
+ if (!feof(inFile)) {
+ close(outFd);
+ fclose(inFile);
+ throw std::runtime_error(tfm::format("Unknown error while reading %s", inPath));
+ }
+ close(outFd);
+ fclose(inFile);
+}
+
+static void checksum(const char * type, const char * inPath, const char * checksum_valid, bool * valid_out, gchar ** calculated_out)
+{
+ GError * errP{nullptr};
+ gboolean valid;
+ LrChecksumType lr_type = lr_checksum_type(type);
+
+ if (lr_type == LR_CHECKSUM_UNKNOWN)
+ throw libdnf::Error(tfm::format("Unknown checksum type %s", type));
+
+ auto inFd = open(inPath, O_RDONLY);
+
+ if (inFd == -1)
+ throw libdnf::Error(tfm::format("Error opening %s: %s", inPath, strerror(errno)));
+
+ auto ret = lr_checksum_fd_compare(lr_type,
+ inFd,
+ /**
+ * If checksum_valid references a string, pass it in, else use
+ * an empty string
+ */
+ checksum_valid ? checksum_valid : "",
+ TRUE,
+ &valid,
+ calculated_out,
+ &errP);
+
+ close(inFd);
+ if (!ret)
+ throw libdnf::Error(tfm::format("Error calculating checksum %s: (%d, %s)", inPath, errP->code, errP->message));
+ if (valid_out)
+ *valid_out = valid == TRUE; /* gboolean -> bool */
+}
+
+
+bool checksum_check(const char * type, const char * inPath, const char * checksum_valid)
+{
+ bool valid;
+ checksum(type, inPath, checksum_valid, &valid, NULL);
+ return valid;
+}
+
+std::string checksum_value(const char * type, const char * inPath)
+{
+ g_autofree gchar *calculated = NULL;
+ checksum(type, inPath, NULL, NULL, &calculated);
+ std::string out(calculated);
+ return out;
+}
+
+}
+
+namespace numeric {
+int random(const int min, const int max) {
+ std::random_device rd;
+ std::default_random_engine gen(rd());
+ std::uniform_int_distribution<int> dist(min, max);
+ return dist(gen);
+}
+}
+
+}
--- /dev/null
+#ifndef LIBDNF_UTILS_HPP
+#define LIBDNF_UTILS_HPP
+
+#define ASCII_LOWERCASE "abcdefghijklmnopqrstuvwxyz"
+#define ASCII_UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define ASCII_LETTERS ASCII_LOWERCASE ASCII_UPPERCASE
+#define DIGITS "0123456789"
+#define REPOID_CHARS ASCII_LETTERS DIGITS "-_.:"
+
+#include "libdnf/sack/advisory.hpp"
+#include "libdnf/dnf-utils.h"
+
+#include <functional>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+
+namespace libdnf {
+
+/**
+* @brief Object calls user defined function during its destruction.
+*
+* User function is passed as parameter of object constructor.
+* Example with user function defined as lambda:
+*
+* Finalizer finalizerObject([&tmpDirectory](){
+* remove(tmpDirectory);
+* });
+*/
+class Finalizer {
+public:
+ Finalizer(const std::function<void()> & func) : func(func) {}
+ Finalizer(std::function<void()> && func) : func(std::move(func)) {}
+ ~Finalizer() { func(); }
+private:
+ std::function<void()> func;
+};
+
+DEPRECATED("advisory now provides getApplicablePackages and each AdvisoryModule provides isApplicable.")
+bool isAdvisoryApplicable(Advisory & advisory, DnfSack * sack);
+
+namespace string {
+inline std::string fromCstring(const char * cstring) { return cstring ? cstring : ""; }
+std::vector<std::string> split(const std::string &source, const char *delimiter, int maxSplit = -1);
+std::vector<std::string> rsplit(const std::string &source, const char *delimiter, int maxSplit = -1);
+std::string trimSuffix(const std::string &source, const std::string &suffix);
+std::string trimPrefix(const std::string &source, const std::string &prefix);
+std::string trim(const std::string &source);
+bool startsWith(const std::string &source, const std::string &toMatch);
+bool endsWith(const std::string &source, const std::string &toMatch);
+}
+
+bool haveFilesSameContent(const char * filePath1, const char * filePath2);
+bool updateFile(const char * filePath, const char * newFileContent);
+
+namespace filesystem {
+bool exists (const std::string &name);
+bool isDIR(const std::string& dirPath);
+std::vector<std::string> getDirContent(const std::string &dirPath);
+
+/**
+* @brief Decompress file.
+*
+* @param inPath Path to input (compressed) file
+* @param outPath Path to output (decompressed) file
+* @param outMode Mode of created (output) file
+* @param compressType Type of compression (".bz2", ".gz", ...), nullptr - detect from inPath filename. Defaults to nullptr.
+*/
+void decompress(const char * inPath, const char * outPath, mode_t outMode, const char * compressType = nullptr);
+
+/**
+* @brief checksum file and return if matching.
+*
+* @param type Checksum type ("sha", "sha1", "sha256" etc). Raises libdnf::Error if invalid.
+* @param inPath Path to input file
+* @param valid_checksum hexadecimal encoded checksum string.
+*/
+bool checksum_check(const char * type, const char * inPath, const char * valid_checksum);
+/**
+* @brief checksum file and return checksum.
+*
+* @param type Checksum type ("sha", "sha1", "sha256" etc). Raises libdnf::Error if invalid.
+* @param inPath Path to input file
+*/
+std::string checksum_value(const char * type, const char * inPath);
+}
+
+namespace numeric {
+/**
+* @brief Return a random number in the given range.
+*
+* Each possible value has an equal likelihood of being produced.
+*
+* @param min lower bound of the range
+* @param max upper bound of the range
+*/
+int random(const int min, const int max);
+}
+
+}
+
+#endif //LIBDNF_UTILS_HPP
--- /dev/null
+all: example_plugin
+
+example_plugin: example_plugin.c
+ gcc -fPIC -shared $(shell pkg-config --cflags --libs libdnf) -Wcast-align -Wno-uninitialized -Wredundant-decls -Wwrite-strings -Wformat-nonliteral -Wmissing-format-attribute -Wsign-compare -Wtype-limits -Wuninitialized -Wall -Werror=implicit-function-declaration -Wl,--as-needed -Wmissing-prototypes -Waggregate-return -Wshadow -o example_plugin.so example_plugin.c
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This is example libdnf plugin. It works with applications that uses "context" libdnf API
+ * (eg. microdnf and PackageKit).
+ * The plugin writes information about repositories in the context and about packages in
+ * the goal into the file.
+ */
+
+#define OUT_FILE_PATH "/tmp/libdnf_test_plugin.log"
+
+#include <libdnf/plugin/plugin.h>
+#include <libdnf/libdnf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Information about this plugin
+// Pointer to this structure is returned by pluginGetInfo().
+static const PluginInfo info = {
+ .name = "ExamplePlugin",
+ .version = "1.0.0"
+};
+
+// Plugin instance private data
+// Pointer to instance of this structure is returned by pluginInitHandle() as handle.
+struct _PluginHandle
+{
+ PluginMode mode;
+ DnfContext * context; // store plugin context specific init data
+ FILE * outStream; // stream to write output
+};
+
+// Returns general information about this plugin.
+// Can be called at any time.
+const PluginInfo * pluginGetInfo(void)
+{
+ return &info;
+}
+
+// Creates new instance of this plugin. Returns its handle.
+PluginHandle * pluginInitHandle(int version, PluginMode mode, DnfPluginInitData * initData)
+{
+ PluginHandle * handle = NULL;
+ FILE * outStream = fopen(OUT_FILE_PATH, "a");
+ if (!outStream)
+ return handle;
+
+ do {
+ fprintf(outStream, "===============================================================\n");
+ fprintf(outStream, "%s: %s: enter =========================\n", info.name, __func__);
+ fprintf(outStream, "Plugin version=\"%s\", received API version=%i, received mode=\"%i\"\n",
+ info.version, version, mode);
+ if (version != 1) {
+ fprintf(outStream, "%s: %s: Error: Unsupported API version\n", info.name, __func__);
+ break;
+ }
+ if (mode != PLUGIN_MODE_CONTEXT) {
+ fprintf(outStream, "%s: %s: Warning: Unsupported mode\n", info.name, __func__);
+ break;
+ }
+ handle = malloc(sizeof(*handle));
+ if (handle) {
+ handle->mode = mode;
+ handle->context = pluginGetContext(initData);
+ handle->outStream = outStream;
+ }
+ } while (0);
+
+ fprintf(outStream, "%s: %s: exit =========================\n", info.name, __func__);
+ if (handle)
+ fflush(outStream);
+ else
+ fclose(outStream);
+ return handle;
+}
+
+// Destroys the plugin instance identified by given handle.
+void pluginFreeHandle(PluginHandle * handle)
+{
+ if (handle) {
+ fprintf(handle->outStream, "%s: %s: ===========================\n", info.name, __func__);
+ fprintf(handle->outStream, "===============================================================\n\n");
+ fclose(handle->outStream);
+ free(handle);
+ }
+}
+
+// Writes a list of "packages". For each package is written a list of packages
+// thats are upgraded/downgraded/obsoleted by this package. These packages are added into
+// the "obsoleted" array.
+static void writeInfo(FILE * f, HyGoal goal, GPtrArray * packages, GPtrArray * obsoleted,
+ const char * header, const char * obsoleteText)
+{
+ if (packages->len == 0)
+ return;
+ fprintf(f, "%s", header);
+ for (unsigned int i = 0; i < packages->len; ++i) {
+ DnfPackage * pkg = g_ptr_array_index(packages, i);
+ fprintf(f, " %s@%s\n", dnf_package_get_nevra(pkg), dnf_package_get_reponame(pkg));
+
+ // list of upgraded, downgraded, obsoleted packages
+ g_autoptr(GPtrArray) obsoletedPackages = hy_goal_list_obsoleted_by_package(goal, pkg);
+ for (unsigned int obsIdx = 0; obsIdx < obsoletedPackages->len; ++obsIdx) {
+ DnfPackage * obsPkg = g_ptr_array_index(obsoletedPackages, obsIdx);
+ fprintf(f, " %-25s%s\n", obsoleteText, dnf_package_get_nevra(obsPkg));
+
+ // Package can be obsoleted by more packages.
+ // Do not add it into the "obsoleted" array more that once.
+ gboolean found = FALSE;
+ for (unsigned int allObsIdx = 0; allObsIdx < obsoleted->len; ++allObsIdx) {
+ found = dnf_package_get_identical(g_ptr_array_index(obsoleted, allObsIdx), obsPkg);
+ if (found)
+ break;
+ }
+ if (!found)
+ g_ptr_array_add(obsoleted, g_object_ref(obsPkg));
+ }
+ }
+}
+
+int pluginHook(PluginHandle * handle, PluginHookId id, DnfPluginHookData * hookData, DnfPluginError * error)
+{
+ if (!handle)
+ return 1;
+ fprintf(handle->outStream, "%s: %s: id=%i enter ========================\n", info.name, __func__, id);
+ switch (id) {
+ case PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION:
+ fprintf(handle->outStream, "Info before libdnf context transaction run:\n");
+
+ // write info about loaded repos
+ fprintf(handle->outStream, "Info about loaded repos:\n");
+ GPtrArray * repos = dnf_context_get_repos(handle->context);
+ for (unsigned int i = 0; i < repos->len; ++i) {
+ DnfRepo * repo = g_ptr_array_index(repos, i);
+ const gchar * repoId = dnf_repo_get_id(repo);
+ g_autofree gchar * description = dnf_repo_get_description(repo);
+ bool enabled = (dnf_repo_get_enabled(repo) & DNF_REPO_ENABLED_PACKAGES) > 0;
+ fprintf(handle->outStream, "Repo enabled=%i, repoId=%s, repoDescr=\"%s\"\n", enabled, repoId, description);
+ }
+
+ // write info about packages in goal
+ fprintf(handle->outStream, "Info about packages in goal:\n");
+ HyGoal goal = hookContextTransactionGetGoal(hookData);
+ if (goal) {
+
+ // "obsoleted" array will be filled with obsoleted/updated/downgraded packages
+ g_autoptr(GPtrArray) obsoleted = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
+
+ GPtrArray * packages = hy_goal_list_installs(goal, NULL);
+ if (packages) {
+ writeInfo(handle->outStream, goal, packages, obsoleted, "Install:\n", "obsoleted");
+ g_ptr_array_unref(packages);
+ }
+ packages = hy_goal_list_reinstalls(goal, NULL);
+ if (packages) {
+ writeInfo(handle->outStream, goal, packages, obsoleted, "Reinstall:\n", "obsoleted");
+ g_ptr_array_unref(packages);
+ }
+ packages = hy_goal_list_downgrades(goal, NULL);
+ if (packages) {
+ writeInfo(handle->outStream, goal, packages, obsoleted, "Downgrade:\n", "downgraded/obsoleted");
+ g_ptr_array_unref(packages);
+ }
+ packages = hy_goal_list_upgrades(goal, NULL);
+ if (packages) {
+ writeInfo(handle->outStream, goal, packages, obsoleted, "Upgrade:\n", "upgraded/obsoleted");
+ g_ptr_array_unref(packages);
+ }
+ packages = hy_goal_list_erasures(goal, NULL);
+ if (packages) {
+ if (packages->len)
+ fprintf(handle->outStream, "Remove:\n");
+ for (unsigned int i = 0; i < packages->len; ++i) {
+ DnfPackage * pkg = g_ptr_array_index(packages, i);
+ fprintf(handle->outStream, " %s\n", dnf_package_get_nevra(pkg));
+ }
+ g_ptr_array_unref(packages);
+ }
+ if (obsoleted->len) {
+ fprintf(handle->outStream, "Summary of upgraded, downgraded, obsoleted:\n");
+ for (unsigned int i = 0; i < obsoleted->len; ++i) {
+ DnfPackage * pkg = g_ptr_array_index(obsoleted, i);
+ fprintf(handle->outStream, " %s\n", dnf_package_get_nevra(pkg));
+ g_autoptr(GPtrArray) obsoletedByPackages = hy_goal_list_obsoleted_by_package(goal, pkg);
+ for (unsigned int obsIdx = 0; obsIdx < obsoletedByPackages->len; ++obsIdx) {
+ DnfPackage * obsPkg = g_ptr_array_index(obsoletedByPackages, obsIdx);
+ fprintf(handle->outStream, " %-25s%s@%s\n", "by",
+ dnf_package_get_nevra(obsPkg), dnf_package_get_reponame(obsPkg));
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ fprintf(handle->outStream, "%s: %s: id=%i exit ========================\n", info.name, __func__, id);
+ fflush(handle->outStream);
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <libdnf/plugin/plugin.h>
+#include <libdnf/libdnf.h>
+#include <libdnf/log.hpp>
+#include <rhsm/rhsm.h>
+
+#include <string>
+
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+// Information about this plugin
+// Pointer to this structure is returned by pluginGetInfo().
+static const PluginInfo info = {
+ .name = "rhsm",
+ .version = "1.0.0"
+};
+
+// plugin context private data
+// Pointer to instance of this structure is returned by pluginInitHandle() as handle.
+struct _PluginHandle
+{
+ PluginMode mode;
+ DnfContext * context; // store plugin context specific init data
+};
+
+const PluginInfo * pluginGetInfo(void)
+{
+ return &info;
+}
+
+PluginHandle * pluginInitHandle(int version, PluginMode mode, DnfPluginInitData * initData)
+{
+ auto logger(libdnf::Log::getLogger());
+ if (version != 1) {
+ auto msg = std::string(info.name) + ": " + __func__ + ": Error: Unsupported API version";
+ logger->error(msg);
+ return nullptr;
+ }
+ if (mode != PLUGIN_MODE_CONTEXT) {
+ auto msg = std::string(info.name) + ": " + __func__ + ": Warning: Unsupported mode";
+ logger->warning(msg);
+ return nullptr;
+ }
+ auto handle = new PluginHandle;
+ handle->mode = mode;
+ handle->context = pluginGetContext(initData);
+ return handle;
+}
+
+void pluginFreeHandle(PluginHandle * handle)
+{
+ if (handle)
+ delete handle;
+}
+
+/**
+ * dnf_context_setup_enrollments:
+ * @context: a #DnfContext instance.
+ *
+ * Resyncs the enrollment with the vendor system. This may change the contents
+ * of files in repos.d according to subscription levels.
+ *
+ * Returns: %true for success, %false otherwise
+ **/
+static bool setupEnrollments(PluginHandle *handle)
+{
+ auto logger(libdnf::Log::getLogger());
+
+ if (dnf_context_get_cache_only(handle->context))
+ return true;
+
+ /* Let's assume that alternative installation roots don't
+ * require entitlement. We only want to do system things if
+ * we're actually affecting the system. A more accurate test
+ * here would be checking that we're using /etc/yum.repos.d or
+ * so, but that can come later.
+ */
+ auto installRoot = dnf_context_get_install_root(handle->context);
+ if (installRoot && strcmp(installRoot, "/") != 0)
+ return true;
+
+ /* Also, all of the subman stuff only works as root, if we're not
+ * root, assume we're running in the test suite, or we're part of
+ * e.g. rpm-ostree which is trying to run totally as non-root.
+ */
+ if (getuid() != 0)
+ return true;
+
+ auto repoDir = dnf_context_get_repo_dir(handle->context);
+ g_autofree gchar *repofname = g_build_filename(repoDir, "redhat.repo", NULL);
+
+ g_autoptr(RHSMContext) rhsm_ctx = rhsm_context_new();
+ g_autoptr(GKeyFile) repofile = rhsm_utils_yum_repo_from_context(rhsm_ctx);
+
+ /* We don't want rewrite "redhat.repo" file with the same content.
+ * So we do a comparison of contents. Only If file is missing or
+ * contents differs new content is written to the file.
+ */
+ bool sameContent = false;
+ int fd;
+ if ((fd = open(repofname, O_RDONLY)) != -1) {
+ gsize length;
+ g_autofree gchar *data = g_key_file_to_data(repofile, &length, NULL);
+ auto fileLen = lseek(fd, 0, SEEK_END);
+ if (fileLen == static_cast<long>(length)) {
+ if (fileLen > 0) {
+ auto addr = mmap(NULL, fileLen, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr != reinterpret_cast<void *>(-1)) {
+ sameContent = memcmp(addr, data, fileLen) == 0;
+ munmap(addr, fileLen);
+ }
+ } else {
+ sameContent = true;
+ }
+ }
+ close(fd);
+ }
+ if (!sameContent) {
+ GError * error = nullptr;
+ if (!g_key_file_save_to_file(repofile, repofname, &error)) {
+ logger->error(std::string(info.name) + ": " + __func__ + ": Error: Can't save repo file: " + error->message);
+ g_error_free(error);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int pluginHook(PluginHandle * handle, PluginHookId id, DnfPluginHookData * hookData, DnfPluginError * error)
+{
+ if (!handle)
+ return 1;
+
+ switch (id) {
+ case PLUGIN_HOOK_ID_CONTEXT_PRE_REPOS_RELOAD:
+ return setupEnrollments(handle);
+ default:
+ break;
+ }
+ return 1;
+}
--- /dev/null
+# pulling translations from weblate
+
+set(WEBLATE_REPO_URL "git@github.com:rpm-software-management/${PROJECT_NAME}-l10n.git")
+set(WEBLATE_REPO_BRANCH "master")
+set(WEBLATE_REPO_PATH ${CMAKE_CURRENT_BINARY_DIR}/tmp-weblate-repo)
+
+find_package(Git)
+find_package(Gettext)
+
+if (GIT_FOUND)
+ # detect current git branch
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} symbolic-ref --short -q HEAD
+ COMMAND tr -d '[:space:]'
+ OUTPUT_VARIABLE CURRENT_BRANCH
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ # output _weblate-clone is never created so the clonning of weblate repo is always processed
+ # and fresh *.po files are used
+ add_custom_command(OUTPUT _weblate-clone
+ COMMENT "Clonning weblate repo"
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${WEBLATE_REPO_PATH}
+ COMMAND ${GIT_EXECUTABLE} clone --depth=1 -b ${WEBLATE_REPO_BRANCH} ${WEBLATE_REPO_URL} ${WEBLATE_REPO_PATH}
+ BYPRODUCTS ${WEBLATE_REPO_PATH}
+ )
+
+ add_custom_target(gettext-update
+ COMMENT "Updating translation files from weblate repo"
+
+ COMMAND ${CMAKE_COMMAND} -E copy ${WEBLATE_REPO_PATH}/${CURRENT_BRANCH}/*.po .
+ COMMAND ${CMAKE_COMMAND} -E copy ${WEBLATE_REPO_PATH}/${CURRENT_BRANCH}/${PROJECT_NAME}.pot .
+ COMMAND ${WEBLATE_REPO_PATH}/script/sanitize_po_files.py *.po
+
+ DEPENDS _weblate-clone
+
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+endif()
+
+add_custom_target(gettext-pot
+ COMMENT "Generating fresh dnf.pot file from sources"
+
+ COMMAND find . -iname '*.[ch]' -o -iname '*.[ch]pp' |
+ xargs xgettext -F --from-code=UTF-8 --keyword=_ --keyword=M_ --keyword=P_:1,2 --keyword=MP_:1,2 --keyword=C_:1c,2 --keyword=MC_:1c,2 --keyword=CP_:1c,2,3 --keyword=MCP_:1c,2,3 -c --output=${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pot
+
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ )
+
+IF (GETTEXT_FOUND)
+ # this process unfortunately reformats .po files so copy them
+ FILE(GLOB POS ${CMAKE_CURRENT_SOURCE_DIR}/*.po)
+ FILE(COPY ${POS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+ FILE(GLOB POS_BIN ${CMAKE_CURRENT_BINARY_DIR}/*.po)
+ GETTEXT_CREATE_TRANSLATIONS(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pot ALL ${POS_BIN})
+ENDIF()
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 02:50+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Assamese\n"
+"Language: as\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "চলমান"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Valentin Laskov <laskov@festa.bg>, 2016. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2016-11-21 05:57+0000\n"
+"Last-Translator: Valentin Laskov <laskov@festa.bg>\n"
+"Language-Team: Bulgarian\n"
+"Language: bg\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "не е зададена стойност"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "невалидна двоична стойност '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "зададеният път '%s' не е абсолютен."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "зададеният път '%s' не съществува."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Abu Huraira <abuhuraira@tutamail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2021-04-04 06:01+0000\n"
+"Last-Translator: Abu Huraira <abuhuraira@tutamail.com>\n"
+"Language-Team: Bengali <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/bn/>\n"
+"Language: bn\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Weblate 4.5.3\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "কোনও মান নির্দিষ্ট করা হয়নি"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "সেকেন্ডের মান '%s' অবশ্যই নেতিবাচক হওয়া উচিত নয়"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "'%s' কে বাইটে রূপান্তর করা যায়নি"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "অজানা ইউনিট '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "অবৈধ মান"
+
+#: libdnf/conf/ConfigMain.cpp:207
+#, fuzzy
+#| msgid "'%s' is not an allowed value"
+msgid "value 1 is not allowed"
+msgstr "'%s' একটি অনুমোদিত মান নয়"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "শতাংশ '%s' সীমার বাইরে"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "কনফিগারেশন: \"%s\" আইডি সহ অপশনবাইন্ডিংয়ের অস্তিত্ব নেই"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "কনফিগারেশন: \"%s\" আইডি সহ অপশনবাইন্ডিং ইতিমধ্যে বিদ্যমান"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "অবৈধ বুলিয়ান মান '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' একটি অনুমোদিত মান নয়"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "প্রদত্ত মান [%d] অনুমোদিত মান [%d] এর চেয়ে কম হওয়া উচিত।"
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "প্রদত্ত মান [%d] অনুমোদিত মান [%d] এর চেয়ে বেশি হওয়া উচিত।"
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "প্রদত্ত পাথ %s নিখুঁত নয়।"
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "প্রদত্ত পাথ '%s' পাওয়া যায়নি।"
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "'%s' টি সেকেন্ডে কনভার্ট করা সম্ভব হয়নি"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): মান সেট করা নেই"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "মডিউল '%s' থেকে একই সময়ে আরও স্ট্রিম সক্রিয় করা সম্ভব নয়"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"মডিউল '%1$s' স্ট্রিম '%2$s' সক্রিয় করা সম্ভব না: মডিউল অবস্থাটি ইতিমধ্যে "
+"সংশোধিত"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "ডিফল্টগুলির সাথে মডুলার নির্ভরতা সমস্যা: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "সর্বশেষতম মডিউলগুলির সাথে মডুলার নির্ভরতা সমস্যা: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "মডুলার নির্ভরতা সমস্যা: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "'%s' যুক্তি সমাধান করতে অক্ষম"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "চলমান"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 02:52+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Bengali (India)\n"
+"Language: bn_IN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "চলমান"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>, 2016. #zanata
+# Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>, 2017. #zanata
+# Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>, 2018. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2018-10-24 09:32+0000\n"
+"Last-Translator: Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>\n"
+"Language-Team: Catalan\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "no s'ha especificat cap valor"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "el valor en segons de «%s» no ha de ser negatiu"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unitat desconeguda «%s»"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+#, fuzzy
+#| msgid "'%s' is not an allowed value"
+msgid "value 1 is not allowed"
+msgstr "«%s» no és un valor permès"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "el percentatge «%s» està fora de l'interval"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "el valor booleà «%s» no és vàlid"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "«%s» no és un valor permès"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "el valor donat [%d] hauria de ser més petit que el valor permès [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "el valor donat [%d] hauria de ser més gran que el valor permès [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "el camí indicat «%s» no és absolut."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "el camí indicat «%s» no existeix."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problema %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problema: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "no hi ha cap solució, no es pot eliminar el paquet protegit"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "no hi ha cap solució possible"
+
+#: libdnf/goal/Goal.cpp:1323
+#, fuzzy
+#| msgid " Problem: %s\n"
+msgid "Problem: "
+msgstr "Problema: %s "
+
+#: libdnf/goal/Goal.cpp:1328
+#, fuzzy, c-format
+#| msgid " Problem: %s\n"
+msgid "Problem %d: "
+msgstr "Problema: %s "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "El dipòsit %s no té establerta cap rèplica o url base."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"La velocitat màxima de baixada és inferior que la mínima. Canvieu la "
+"configuració de minrate o throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "No es pot trobar un url base vàlid per al dipòsit: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "dipòsit: s'utilitza la memòria cau per: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "En progrés"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Zdenek <chmelarz@gmail.com>, 2016. #zanata
+# Zdenek <chmelarz@gmail.com>, 2017. #zanata
+# Jaroslav Rohel <jrohel@redhat.com>, 2018. #zanata
+# Pavel Borecki <pavel.borecki@gmail.com>, 2023.
+# Jan Kalabza <jan.kalabza@gmail.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-08-10 14:21+0000\n"
+"Last-Translator: Jan Kalabza <jan.kalabza@gmail.com>\n"
+"Language-Team: Czech <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/cs/>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"X-Generator: Weblate 4.18.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nezadána hodnota"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "druhá hodnota '%s' nesmí být záporná"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "nepodařilo se převést „%s“ na bajty"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "neznámá jednotka '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "neplatná hodnota"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "hodnota 1 není povolena"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "záporná hodnota není povolena"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "Procento '%s' je mimo rozsah"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Nastavení: OptionBinding s identifikátorem „%s“ neexistuje"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Nastavení: OptionBinding s identifikátorem „%s“ již existuje"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "neplatná pravdivostní hodnota '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' není platná hodnota"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "daná hodnota [%d] by měla být nižší než povolená hodnota [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "daná hodnota [%d] by měla být vyšší než povolená hodnota [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "zadaná cesta '%s' není absolutní."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "zadaná cesta '%s' neexistuje."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "nepodařilo se převést ‘%s‘ na sekundy"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Hodnota není nastavena"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Nelze povolit více streamů z modulu '%s' současně"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Problém modulárních závislostí s Defaults: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Problém modulárních závislostí s nejnovějšími moduly: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Problém modulární závislosti: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Nelze vyřešit argument '%s'"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Nejsou k dispozici žádné modulární údaje"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ignorování nepotřebných informací v argumentu: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr "Operace by vedla k přepnutí streamu modulu '%s' '%s' na stream '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Nelze vyřešit transakci; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i problém detekován:\n"
+msgstr[1] "%i problémů detekováno:\n"
+msgstr[2] "%i problémů detekováno:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problém %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problém: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Pro modulární balíček '%s' nejsou k dispozici modulární metadata; v systému "
+"jej nelze nainstalovat"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "podpis se neověřuje pro %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "se nepodařilo otevřít(obecná chyba): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "nepodařilo se ověřit klíč pro %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "veřejný klíč není k dispozici pro %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "nebyl nalezen podpis pro %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "nepodařilo se přidat instalační prvek: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Chyba při provádění transakce: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "Chybný běh transakce a nebyly hlášeny žádné problémy!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Fatální chyba, spusťte obnovení databáze"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "nepodařilo se najít balíček %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "nepodařilo se přidat prvek %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "funkce repo_add_solv() selhala."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "žádný řetězec %1$s pro %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "nemohu otevřít: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "nelze vytvořit dočasný soubor: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "nepodařilo se otevřít soubor tmp: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "nelze vytvořit dočasný soubor %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo md soubor"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "nelze přečíst soubor %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "načtení MD_TYPE_PRIMARY se nezdařilo."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "nepodařilo se automaticky detekovat architekturu"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "nepodařilo se vytvořit cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "nepodařilo se načíst RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "procentní podíl není 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "se nepodařilo nastavit počet kroků: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "zrušeno zásahem uživatele"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "provedeno na stavu %1$p, který neměl nastavenou velikost! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "již ve 100%% stavu [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Při pokusu o zajištění balíčku %s nebyly nastaveny zdroje"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Nepodařilo se zajistit %1$s, protože repozitář %2$s nebyl nalezen(%3$i "
+"repozitáře načteny)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Nepodařilo se zkontrolovat nedůvěryhodné: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Stažený soubor pro %s nebyl nalezen"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "balíček %1$s nelze ověřit a repozitář %2$s má povoleno GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Nepodařilo se získat hodnotu pro CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Nepodařilo se získat volnou velikost souborového systému pro %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Nepodařilo se získat volnou velikost souborového systému pro %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Nedostatek volného místa v %1$s: potřeba %2$s, k dispozici %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "nepodařilo se nastavit root"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Chyba %i při provádění testu transakce"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Chyba %i probíhající transakce"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "Transakce nepřešla do fáze zápisu, ale nevrátila žádnou chybu(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "nelze otevřít složku %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "nepodařilo se odstranit %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "Pro operaci byl použit nesprávný selektor, nesprávný typ porovnání"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "Pro operaci byl použit nesprávný selektor, nesprávný typ porovnání"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problém s nainstalovaným balíčkem "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "protichůdné požadavky"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "nepodporovaný požadavek"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "nic neposkytuje požadované "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "balíček %s neexistuje"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " je poskytována systémem"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "nějaký problém se závislostí"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "nelze nainstalovat nejlepšího kandidáta na aktualizaci balíčku "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "nemůže instalovat nejlepšího kandidáta pro danou práci"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "problém s nainstalovaným modulem "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "modul %s neexistuje"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "nelze nainstalovat nejlepší kandidáta na aktualizaci modulu "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "není nastaven žádný řešitel"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "nepodařilo se vytvořit %s absolutně"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "nepodařilo se zapsat debugdata do %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "žádný solv v cíli"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "žádné řešení, nelze odstranit chráněný balíček"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "žádné řešení není možné"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Operace by vedla k odstranění následujících chráněných balíčků: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Nepodařilo se přejmenovat %1$s na %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Nepodařilo se nastavit trvalou na %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "nelze vytvořit složku %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "nelze zadat cestu %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Nesprávný formát modulu Platformy: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Více platforem modulů poskytovaných dostupnými balíčky\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Více platforem modulů poskytovaných nainstalovanými balíčky\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Detekce modulu Platformy v %s selhala: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Chybějící PLATFORM_ID v %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Nebylo zjištěno žádné platné ID platformy"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Nelze povolit více toků pro modul '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Konfliktní výchozí nastavení s repozitářem '%s': %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Instalace profilu modulu:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Zakázání profilu modulu:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Povolení modulu stream:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Zakázání modulů:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Resetování modulů:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Nepodařilo se načíst modulární data Fail-Safe na '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "Nelze načíst modulární Fail-Safe data pro modul '%s:%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Nelze vytvořit adresář \"%s\" pro modulární data systému Fail Safe: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Nelze uložit modulární data Fail Safe do '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Nelze odstranit modulární data Fail Safe v '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Nepodařilo se aktualizovat z řetězce: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Nepodařilo se přeložit: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Nepodařilo se aktualizovat výchozí nastavení: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Nepodařilo se aktualizovat stream: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Nelze načíst sdílenou knihovnu \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Nelze získat adresu symbolu \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Načítání souboru pluginu=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Nahráno jméno pluginu=\"%s\", verze=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath nemůže být prázdná"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Nelze přečíst adresář zásuvných modulů \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Nelze načíst zásuvný modul \"%s\": %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Nelze vytvořit dočasný adresář repozitáře \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Repozitář %s nemá nastaveno žádné zrcadlo nebo baseurl."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "Úložiště '%s' má nepodporovaný typ: 'type=%s', vynecháváme."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Maximální rychlost stahování je nižší než minimální. Změňte prosím "
+"konfiguraci minrate nebo omezení"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Nelze najít platný baseURL pro repo: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Nepodařilo se načíst klíč GPG pro repozitář '%s': %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0x%s již importováno"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: importovaný klíč 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "oživení: repozitář '%s' přeskočen, žádný MetaLink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "oživení: repozitář '%s' přeskočen, žádný použitelný hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "oživení: selhalo pro '%s', neshodující se součet %s."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"oživení: '%s' může být oživen - kontrolní součty MetaLinku odpovídají."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "oživení: '%s' může být oživen - repomd se shoduje."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "oživení: selhalo pro '%s', neshodující se repomd."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Nelze vytvořit cílový adresář repozitáře \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Nedaří se vytvořit složku \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Nelze přejmenovat adresář \"%s\" na \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repozitář: použití mezipaměti pro: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Povoleno použítí jen mezipaměti, ale žádná vyrovnávací paměť pro '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: stahování ze vzdáleného serveru: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Nepodařilo se stáhnout metadata pro repo '%s': %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): Výpočet SHA256 se nezdařil"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Nelze vytvořit persistdir \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume nelze použít současně s parametrem byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Inicializace PackageTarget se nezdařila: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Není možné otevřít %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Obsluha protokolu s id %ld neexistuje"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "V přípravě"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Neprovádí se"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Žádná transakce neprobíhá"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Pokus o vložení položky transakce do dokončené transakce"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Pokus o aktualizaci položky transakce v dokončené transakci"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: nelze otevřít historii persist dir"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Nepodařilo se najít databázi historie"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Transakce již začala!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Stav TransactionItem není nastaven: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Nelze přidat výstup konzoly do neuložené transakce"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "nelze vypsat klíče: %s"
--- /dev/null
+# scootergrisen <scootergrisen@gmail.com>, 2017. #zanata, 2020.
+# scootergrisen <scootergrisen@gmail.com>, 2018. #zanata, 2020.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2020-12-31 06:36+0000\n"
+"Last-Translator: scootergrisen <scootergrisen@gmail.com>\n"
+"Language-Team: Danish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/da/>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.4\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "ingen værdi angivet"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "ukendt enhed '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "Ugyldig boolesk værdi '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "givne sti '%s' findes ikke."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, fuzzy, c-format
+#| msgid "some dependency problem"
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "nogle afhængighedsproblemer"
+
+#: libdnf/dnf-context.cpp:3307
+#, fuzzy, c-format
+#| msgid "some dependency problem"
+msgid "Modular dependency problem: %s"
+msgstr "nogle afhængighedsproblemer"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Kan ikke løse argumentet '%s'"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Der kræves kun modulnavn. Ignorerer unødvendige informationer i argument: "
+"'%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Handlingen ville resultere i skift af modulet '%s' strømmen '%s' til "
+"strømmen '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Det er ikke muligt at skifte aktiverede strømme for et modul.\n"
+"Det anbefales at fjerne alt installeret indhold fra modulet, og nulstille modulet med 'dnf module reset <modulnavn>'-kommandoen. Når du har nulstillet moduler, så kan du installere den anden strøm."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Ingen tilgængelig modulær metadata for den modulære pakke '%s', den kan ikke"
+" installeres på systemet"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "kunne ikke åbne: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "kan ikke oprette midlertidig fil: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "kan ikke oprette midlertidig fil %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "nogle afhængighedsproblemer"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "pakken %s er ikke installerbar"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "pakken %s er ikke installerbar"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "softwarearkivet %s: 0x%s allerede importeret"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "softwarearkivet %s: importeret nøgle 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Kan ikke åbne %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Under udførelse"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Dårligt id for softwarearkiv: %s, byte = %s %d"
--- /dev/null
+# Florian H. <postfuerflo@gmail.com>, 2017. #zanata
+# Roman Spirgi <bigant@fedoraproject.org>, 2017. #zanata
+# Tobias Weise <tobias.weise@web.de>, 2017. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Paul Ritter <paul-ritter@gmx.net>, 2018. #zanata
+# Fabian Affolter <mail@fabian-affolter.ch>, 2020.
+# Ettore Atalan <atalanttore@googlemail.com>, 2021, 2022.
+# Philipp Trulson <philipp@trulson.de>, 2022.
+# Joachim Philipp <joachim.philipp@gmail.com>, 2022.
+# Marius Kamp <msk@posteo.org>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2022-12-30 11:19+0000\n"
+"Last-Translator: Marius Kamp <msk@posteo.org>\n"
+"Language-Team: German <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/de/>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.15\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "Kein Wert angegeben"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "Der Wert für Sekunden '%s' darf nicht negativ sein"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "konnte nicht konvertieren%s'in Bytes"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "Unbekannte Einheit '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "Ungültiger Wert"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "Wert 1 ist nicht erlaubt"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "negativer Wert ist nicht erlaubt"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "Prozentsatz '%s' liegt außerhalb des zulässigen Bereichs"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Konfiguration: OptionBinding mit ID \"%s\" ist nicht vorhanden"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Konfiguration: OptionBinding mit ID \"%s\" ist bereits vorhanden"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "Ungültige Boolesche Variable »%s«"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' ist kein zulässiger Wert"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+"Eingegebener Wer [%d] sollte kleiner sein als der zulässige Wert [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "Eingegebener Wer [%d] sollte größer sein als der zulässige Wert [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "Der eingegebene Pfad '%s' ist nicht absolut."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "Der eingegebene Pfad '%s' existiert nicht."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "konnte nicht konvertieren%s'zu Sekunden"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue (): Wert nicht festgelegt"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Kann keine weiteren gleichzeitigen Streams von Modul '%s' einrichten"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Modulares Abhängigkeitsproblem mit den neuesten Modulen: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Modulares Abhängigkeitsproblem: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Keine modularen Daten verfügbar"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Konnte Transaktion nicht depsolven "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i Problem erkannt:\n"
+msgstr[1] "%i Probleme erkannt:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problem %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problem: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "Signatur überprüft nicht %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "Fehler beim Öffnen (generischer Fehler): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "konnte den Schlüssel für nicht bestätigen %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "öffentlicher Schlüssel nicht verfügbar für %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "Signatur für nicht gefunden %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "Installationselement konnte nicht hinzugefügt werden: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Fehler beim Ausführen der Transaktion: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Fehler beim Ausführen der Transaktion und es wurden keine Probleme gemeldet!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Schwerwiegender Fehler, Datenbankwiederherstellung durchführen"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "Paket konnte nicht gefunden werden %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "Erase Element konnte nicht hinzugefügt werden %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() has failed."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "kein %1$s String für %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "Gescheitert zu öffnen: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "temporäre Datei kann nicht erstellt werden: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "Fehler beim Öffnen der tmp-Datei: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, fuzzy, c-format
+#| msgid "failed opening tmp file: %s"
+msgid "Failed closing tmp file %s: %s"
+msgstr "Fehler beim Öffnen der tmp-Datei: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "kann keine temporäre Datei erstellen %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "Null-Repo-MD-Datei"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "kann Datei nicht lesen %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "Das Laden von MD_TYPE_PRIMARY ist fehlgeschlagen."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "Architektur konnte nicht automatisch erkannt werden"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "Fehler beim Erstellen von Cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "Fehler beim Laden der RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "Prozentsatz nicht 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "Anzahl Schritte konnte nicht eingestellt werden: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "durch Benutzeraktion abgebrochen"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+"auf einen Staat gemacht %1$p das hatte keine Größe eingestellt! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "bereits bei 100 %% state [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+"Quellen nicht festgelegt, wenn versucht wird, ein Paket sicherzustellen %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Es konnte nicht sichergestellt werden %1$s als Repo %2$s nicht gefunden(%3$i"
+" Repos geladen)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Fehler beim Überprüfen nicht vertrauenswürdiger Elemente: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Heruntergeladene Datei für %s nicht gefunden"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"Paket %1$s kann nicht überprüft werden und repo %2$s ist GPG aktiviert: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Fehler beim Abrufen des Werts für CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Größe des Dateisystems konnte nicht abgerufen werden %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Größe des Dateisystems konnte nicht abgerufen werden %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Nicht genügend Freiraum in %1$s: erforderlich %2$s, verfügbar %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "root konnte nicht gesetzt werden"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Error %i laufender Transaktionstest"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Error %i laufende Transaktion"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"Transaktion ging nicht in die Schreibphase, gab jedoch keinen Fehler zurück "
+"(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "Verzeichnis kann nicht geöffnet werden %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "konnte nicht entfernt werden %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "gehört nicht zu einer distupgrade-Paketquelle"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "hat eine schlechtere Architektur"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "Problem mit installiertem Paket "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "widersprüchliche Anforderungen"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "nicht unterstützte Anfrage"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "Paket %s existiert nicht"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " wird vom System bereitgestellt"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "irgendein Abhängigkeitsproblem"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+"Installation des besten Update-Kandidaten nicht möglich für das Paket "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "Installation des besten Kandidaten nicht möglich für den Auftrag"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "Paket %s wird durch modulare Filterung herausgefiltert"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "Paket %s hat keine kompatible Architektur"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "Paket %s ist nicht installierbar"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "Paket %s wird durch Ausschlussfilterung herausgefiltert"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "nichts stellt %s bereit, das von %s benötigt wird"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "kann nicht sowohl %s als auch %s installieren"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "Paket %s steht im Konflikt mit %s, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "Paket %s macht %s obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+"installiertes Paket %s macht %s obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "Paket %s macht %s implizit obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"Paket %s erfordert %s, aber keiner der Anbieter kann installiert werden"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "Paket %s steht im Konflikt mit dem von ihm selbst bereitgestellten %s"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "beide Pakete %s und %s machen %s obsolet"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "gehört nicht zu einer distupgrade-Paketquelle"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "hat eine schlechtere Architektur"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "Problem mit installiertem Modul "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "Modul %s existiert nicht"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+"kann nicht den besten Kandidaten für die Aktualisierung des Moduls "
+"installieren "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "Modul %s ist deaktiviert"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "Modul %s hat keine kompatible Architektur"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "Modul %s ist nicht installierbar"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "%s bietet nichts an, was von Modul %s benötigt wird"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "kann nicht beide Module %s und %s installieren"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "Modul %s steht im Konflikt mit %s, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "Modul %s macht %s obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+"installiertes Modul %s macht %s obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "Modul %s macht %s implizit obsolet, das von %s bereitgestellt wird"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"Modul %s erfordert %s, aber keiner der Anbieter kann installiert werden"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "Modul %s steht im Konflikt mit dem von ihm selbst bereitgestellten %s"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "beide Module %s und %s machen %s obsolet"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "kein Auflösungswerkzeug gesetzt"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "keine Lösung, kann geschütztes Paket nicht entfernen"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "keine Lösung möglich"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Problem: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Problem %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+"Die Operation würde dazu führen, dass die folgenden geschützten Pakete "
+"entfernt werden: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Umbenennung von %1$s nach %2$s fehlgeschlagen: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Fehler beim Festlegen von Berechtigungen für %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "kann Verzeichnis %1$s nicht erstellen: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "\"stat\" für Pfad %1$s fehlgeschlagen: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Ungültiges Format des Plattformmoduls: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+"Mehrere Modulplattformen, die durch verfügbare Pakete bereitgestellt "
+"werden\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+"Mehrere Modulplattformen, die von installierten Paketen bereitgestellt "
+"werden\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Erkennung des Plattformmoduls in %s fehlgeschlagen: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Fehlende PLATFORM_ID in %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Keine gültige Plattformkennung erkannt"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Modulprofile werden installiert:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Modulprofile werden deaktiviert:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Module werden deaktiviert:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Module werden zurückgesetzt:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Auflösung fehlgeschlagen: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Repo-Verzeichnis kann nicht erstellt werden \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+"Paketquelle %s weist keine Spiegelserver- oder Baseurl-Einstellung auf."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Die maximale Downloadgeschwindigkeit liegt unter der minimalen "
+"Downloadgeschwindigkeit. Bitte passen Sie die Einstellung von minrate oder "
+"throttle an"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Keine gültige baseurl gefunden für Paketquelle: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "Paketquelle %s: 0x%s bereits importiert"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, fuzzy, c-format
+#| msgid "Cannot create directory \"%s\": %s"
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Verzeichnis kann nicht erstellt werden \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "Repo %s: importierter Schlüssel 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "Widerbeleben: Paketquelle '%s' übersprungen, kein Metalink"
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "Erneuern: Paketquelle '%s' übersprungen, kein benutzbarer Hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "Wiederbeleben: Fehler bei '%s', nicht passende %s Summe."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"Wiederbeleben: '%s' kann wiederbelebt werden - Metalink Prüfsumme gefunden."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "Erneuern: '%s' kann erneuert werden - repomd stimmt überein."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "Wiederbeleben: Fehler bei '%s', nicht übereinstimmende repomd"
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Verzeichnis kann nicht erstellt werden \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Verzeichnis kann nicht umbenannt werden \"%s\"bis\"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "Paketquelle: Cache verwenden für: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "»Nur Cache« aktiviert, aber kein Cache für »%s«"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "Repo: Herunterladen von Remote: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir (): Die Berechnung von SHA256 ist fehlgeschlagen"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"resume kann nicht gleichzeitig mit dem byterangestart-param verwendet werden"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Initialisierung von PackageTarget fehlgeschlagen: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Nicht öffnen können %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Protokollhandler mit ID %ld existiert nicht"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "In Arbeit"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Nicht in Arbeit"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Keine Transaktion in Bearbeitung"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+"Versuchen Sie, das Transaktionselement in die abgeschlossene Transaktion "
+"einzufügen"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+"Versuch, das Transaktionselement in der abgeschlossenen Transaktion zu "
+"aktualisieren"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: kann nicht geöffnet werden"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Konnte keine Verlaufsdatenbank finden"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Die Transaktion hat bereits begonnen!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem-Status ist nicht festgelegt: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+"Konsolenausgabe kann nicht zur nicht gespeicherten Transaktion hinzugefügt "
+"werden"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "kann keine Schlüssel auflisten: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "konnte nicht hinzugefügt werden"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main () konnte Daten nicht schreiben: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main () konnte die geschriebene Solv-Datei nicht erneut laden"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext (%1$d) ist fehlgeschlagen: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() has failed."
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "Fehler beim Berechnen der RPMDB-Prüfsumme"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:00+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Greek\n"
+"Language: el\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Σε εξέλιξη"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Máximo Castañeda Riloba <mcrcctm@gmail.com>, 2016. #zanata
+# Máximo Castañeda Riloba <mcrcctm@gmail.com>, 2017. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Máximo Castañeda Riloba <mcrcctm@gmail.com>, 2018. #zanata
+# Emilio Herrera <ehespinosa57@gmail.com>, 2020, 2021.
+# Alejandro Alcaide <alex@blueselene.com>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2022-05-02 18:18+0000\n"
+"Last-Translator: Alejandro Alcaide <alex@blueselene.com>\n"
+"Language-Team: Spanish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/es/>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.12.1\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "no se ha indicado ningún valor"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "el tiempo (%s) no puede ser negativo"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "no se pudo transformar '%s' en bytes"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unidad '%s' desconocida"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "valor no aceptado"
+
+#: libdnf/conf/ConfigMain.cpp:207
+#, fuzzy
+#| msgid "'%s' is not an allowed value"
+msgid "value 1 is not allowed"
+msgstr "no se admite el valor '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "el valor del porcentaje (%s) se encuentra fuera del rango aceptable"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configuración: no existe OptionBinding con id \"%s\""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configuración: ya existe OptionBinding con id \"%s\""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valor booleano inválido '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "no se admite el valor '%s'"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "el valor [%d] no puede ser mayor que el máximo permitido [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "el valor [%d] no puede ser menor que el mínimo permitido [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "la ruta '%s' no es absoluta."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "la ruta '%s' no existe."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "no se pudo convertir '%s' en segundos"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): valor no definido"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, fuzzy, c-format
+#| msgid "failed to remove %s"
+msgid "Unable to resolve argument '%s'"
+msgstr "no se pudo eliminar %s"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "No se pudo cancelar la transacción; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i problema detectado:\n"
+msgstr[1] "%i problemas detectados:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problema %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problema: %*s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"No hay metadatos modulares disponibles para el paquete modular '%s'; no "
+"puede ser instalado en el sistema"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "la firma no cuadra para %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "no se pudo abrir (error genérico): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "no se pudo verificar la clave para %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "clave pública no disponible para %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "no se encontró la firma para %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "no se pudo añadir el elemento de instalación: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Error al ejecutar la transacción: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"¡Se ha producido un error al ejecutar la transacción, pero no se ha "
+"informado de problemas!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Error fatal, ejecute recuperación de la base de datos"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "no se encontró el paquete %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "no se pudo añadir elemento de borrado %1$s (%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "falló repo_add_solv()."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "ninguna cadena %1$s para %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "no se pudo abrir: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "no se pudo crear archivo temporal: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "no se pudo abrir archivo temporal: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, fuzzy, c-format
+#| msgid "failed opening tmp file: %s"
+msgid "Failed closing tmp file %s: %s"
+msgstr "no se pudo abrir archivo temporal: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "no se pudo crear archivo temporal %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "nulo archivo md repo"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "no se pudo leer archivo %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "la carga de MD_TIPO_PRIMARIO ha fallado."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "no se pudo detectar la arquitectura"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "no se pudo crear el directorio de caché %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "no se pudo cargar la RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "el total no es el 100%%: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "no se pudo fijar el número de pasos: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "cancelado por acción del usuario"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "finalizada tarea en un estado %1$p sin tamaño [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "ya está al 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+"No se han indicado los orígenes al intentar asegurar la inclusión del "
+"paquete %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"No se pudo asegurar la inclusión de %1$s al no encontrar el repositorio %2$s"
+" (%3$i repositorios cargados)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Error al comprobar no confiable: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "No se encuentra el archivo descargado para %s"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"no se puede comprobar el paquete %1$s y el repositorio %2$s tiene GPG "
+"activo: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "No se puedo obtener el valor de CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "No se pudo obtener el espacio libre del sistema de archivos para %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "No se pudo obtener el espacio libre del sistema de archivos para %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"No hay suficiente espacio disponible en %1$s: se necesitan %2$s, hay %3$s "
+"disponibles"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "no se pudo establecer la raíz"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Error %i al ejecutar la prueba de transacción"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Error %i al ejecutar transacción"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"La transacción no llegó a la fase de escritura, pero tampoco devolvió error "
+"(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "no se pudo abrir directorio %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "no se pudo eliminar %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "No pertenece a un repositorio *distupgrade"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "Tiene arquitectura inferior"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problema con el paquete instalado "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "peticiones conflictivas"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "petición no soportada"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "Nada proporciona lo pedido "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "El paquete %s no existe"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " Es proporcionado por el sistema"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s does not exist"
+msgid "package %s from %s is not installable"
+msgstr "El paquete %s no existe"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides requested "
+msgid "nothing provides %s needed by %s from %s"
+msgstr "Nada proporciona lo pedido"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "No pertenece a un repositorio *distupgrade"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "Tiene arquitectura inferior"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "No se pudo crear el directorio temporal \"%s\" del repositorio: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "El repositorio %s no tiene espejos ni URL base."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"La velocidad máxima de descarga es menor que la mínima. Cambie el ajuste de "
+"minrate o throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "No se encuentra URL válida para el repositorio: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: clave 0x%s ya importada"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, fuzzy, c-format
+#| msgid "Cannot create directory \"%s\": %s"
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "No se pudo crear el directorio \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: importada clave 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "reviving: omitido el repositorio '%s', no hay metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "reviving: omitido el repositorio '%s', no se puede usar el hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "reviving: error para '%s', no coincide la suma %s."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"reviving: '%s' se puede reutilizar, las comprobaciones del metalink cuadran."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "reviving: '%s' se puede reutilizar, los metadatos coinciden."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "reviving: no se puede con '%s', los metadatos no coinciden."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "No se pudo crear el directorio \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "No se pudo renombrar el directorio \"%s\" a \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: se usa caché para %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Se ha activado cache-only, pero no hay caché para '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: descargando desde remoto: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): Falló el cálculo de SHA256"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "no se puede usar resume con el parámetro byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Falló la inicialización de PackageTarget: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "No se pudo abrir %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "No hay gestor de informes con id %ld"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "En marcha"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "No está en marcha"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "No hay ninguna transacción en marcha"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Se ha intentado insertar un elemento en una transacción finalizada"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Se ha intentado actualizar un elemento en una transacción finalizada"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+"Transformador: no se puede abrir el historial de directorio persistente"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "No se encontró ninguna base de datos histórica"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "¡La transacción ya se inició!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "No se ha establecido el estado de la transacción: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "No se puede añadir salida a consola para una transacción no guardada"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "no se pueden obtener las claves: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "no se pudo añadir resolutor"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "fallo en write_main() al escribir datos: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr ""
+#~ "write_main () no pudo volver a cargar el archivo de resolución escrito"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "falló write_ext(%1$d): %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "falló repo_add_repomdxml/rpmmd()."
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "no se pudo calcular la suma de comprobación de RPMDB"
--- /dev/null
+# Asier Sarasua Garmendia <asier.sarasua@gmail.com>, 2016. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2016-06-16 03:51+0000\n"
+"Last-Translator: Asier Sarasua Garmendia <asier.sarasua@gmail.com>\n"
+"Language-Team: Basque\n"
+"Language: eu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+
+#~ msgid "Cannot download '%s': %s."
+#~ msgstr "Ezin da '%s' deskargatu: %s."
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Taha Mokhtary <taha490mokh@outlook.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-05-28 14:20+0000\n"
+"Last-Translator: Taha Mokhtary <taha490mokh@outlook.com>\n"
+"Language-Team: Persian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/fa/>\n"
+"Language: fa\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.17\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "هیچ مقداری مشخص نشده است"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "در حال پیشرفت"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Toni Rantala <trantalafilo@gmail.com>, 2017. #zanata
+# Ricky Tigg <ricky.tigg@gmail.com>, 2020, 2021, 2022.
+# Jan Kuparinen <copper_fin@hotmail.com>, 2020, 2021, 2022, 2023.
+# Ville-Pekka Vainio <vpvainio@iki.fi>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-07-19 21:20+0000\n"
+"Last-Translator: Ville-Pekka Vainio <vpvainio@iki.fi>\n"
+"Language-Team: Finnish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/fi/>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.18.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "arvoa ei määritetty"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "sekuntien arvo ”%s” ei saa olla negatiivinen"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "arvoa ”%s” ei voitu muuntaa tavuiksi"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "tuntematon yksikkö ”%s”"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "virheellinen arvo"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "arvo 1 ei ole sallittu"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "negatiivinen arvo ei ole sallittu"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "prosenttiosuus ”%s” on alueen ulkopuolella"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Asetukset: OptionBindingia tunnuksella ”%s” ei ole olemassa"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Asetukset: OptionBinding tunnuksella ”%s” on jo olemassa"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "virheellinen totuusarvo ”%s”"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "”%s” ei ole sallittu arvo"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "annetun arvon [%d] tulisi olla pienempi kuin sallittu arvo [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "annetun arvon [%d] tulisi olla suurempi kuin sallittu arvo [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "annettu polku ”%s” ei ole absoluuttinen."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "annettua polkua ”%s” ei ole olemassa."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "arvoa ”%s” ei pystytty muuntamaan sekunteiksi"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Arvoa ei asetettu"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+"Enempää virtoja moduulista '%s' ei voida ottaa käyttöön samanaikaisesti"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Ei voida ottaa käyttöön moduulia '%1$s' virta '%2$s': Moduulin tilaa jo "
+"muokattu"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Modulaarinen riippuvuusongelma oletusarvojen kanssa: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Modulaarinen riippuvuusongelma viimeisimpien moduuleiden: %s kanssa"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Modulaarinen riippuvuusongelma: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Argumenttia %s ei voida ratkaista"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Vain moduulin nimi vaaditaan. Ohitetaan tarpeettomat tiedot argumentissa: "
+"'%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "Moduulia '%s' ei voi nollata: Moduulin tilaa jo muokattu"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Moduulia '%s' ei voi ottaa pois käytöstä: Moduulin tilaa jo muokattu"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Ei modulaarista tietoa saatavilla"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ohitetaan tarpeettomat tiedot argumentissa: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Ongelma moduulin '%1$s' virran '%2$s': %3$s riippuvuuspuun käyttöönoton "
+"yhteydessä"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Moduulin käyttöönottopyynnössä ilmeni ongelmia:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Moduulimäärityksille '%s' ei löytynyt aktiivisia moduulipaketteja"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Ei voi asentaa moduulia '%s' vikaturvallisesta asennuslähteestä"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "'%s' vastaavaa profiilia ei löytynyt"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Ei vastaavuutta moduulin määrittelylle %s paketille '%s'"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Ongelma moduulin '%1$s' virran '%2$s': %3$s asennuksen yhteydessä"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Moduulin asennuspyynnössä ilmeni ongelmia:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Moduulin nollauspyynnössä ilmeni ongelmia:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Moduulin käyttöönoton poiston pyynnössä ilmeni ongelmia:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr "Toimenpide johtaisi moduulin '%s' vaihtoon virrasta '%s' virtaan '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Moduulin sallittuja virtauksia ei voi vaihtaa.\n"
+"On suositeltavaa poistaa koko moduulista asennetun sisällön ja nollata moduuli komennolla 'microdnf module reset <moduulin_nimi>'. Kun olet nollannut moduulin, voit asentaa toisen virran."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Transaktion riippuvuuksien ratkaiseminen ei onnistunut; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i ongelma havaittu:\n"
+msgstr[1] "%i ongelmaa havaittu:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Ongelma %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Ongelma: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Modulaarisia metatietoja moduulipaketille ”%s” ei ole saatavilla; ei voida "
+"asentaa järjestelmään"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "tiedoston %s allekirjoitus on virheellinen"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "avaaminen epäonnistui (yleinen virhe): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "tiedoston %s allekirjoitus on virheellinen"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "julkista avainta ei ole saatavilla tiedostolle %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "tiedostolle %s ei löydy allekirjoitusta"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "asennuselementin lisääminen epäonnistui: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Virhe suoritettaessa transaktiota: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Transaktion suorittamisessa tapahtui virhe eikä ongelmista ilmoitettu!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Vakava virhe, suorita tietokannan palautus"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "pakettia %s ei löytynyt"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "ei voitu lisätä poistoelementtiä %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() epäonnistui."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Laajennuksen välimuistin lataaminen %s (%d) epäonnistui: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "tiedoston %1$s merkkijono puuttuu, ohjelmistolähde %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "avaaminen epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "väliaikaistiedostoa ei voi luoda: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "tmp-tiedoston avaaminen epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Ensisijaisen välimuistin %s repowriter kirjoitus epäonnistui: %i, virhe: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "tmp-tiedoston sulkeminen epäonnistui %s:%s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+"Äskettäin kirjoitetun ensisijaisen välimuistin käyttö epäonnistui: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Äskettäin kirjoitetun ensisijaisen välimuistin käyttö epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "väliaikaistiedostoa %s ei voi luoda"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Laajennuksen välimuistin %s (%d): repowriter kirjoitus epäonnistui: %i, "
+"virhe: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"Kun kirjoitetaan laajennusvälimuistia (%d): tilapäistä tiedostoa ei voi "
+"sulkea: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+"Äskettäin kirjoitetun laajennuksen välimuistin käyttö epäonnistui: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+"Äskettäin kirjoitetun laajennuksen välimuistin käyttö epäonnistui: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "tyhjä ohjelmistolähteen md-tiedosto"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "ei voida lukea tiedostoa %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Ohjelmistolähteen latauksen aikana %s:n käyttö epäonnistui: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "MD_TYPE_PRIMARY:n lataaminen epäonnistui."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Asennuslähteen ensisijaisten tietojen avaaminen epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Repomd:n lataus epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Primary:n lataus epäonnistui: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "arkkitehtuurin automaattinen tunnistaminen epäonnistui"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "cachedir:n %s luominen epäonnistui"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "RPMDB:n lataaminen epäonnistui"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Moduulin oletuksia ei löytynyt: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "prosenttiosuus ei 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "vaiheiden määrän asettaminen epäonnistui: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "käyttäjä perui"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "tehty tilassa %1$p, jonka kokoa ei ole asetettu! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "jo 100 %% tilassa [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Lähteitä ei asetettu yritettäessä varmistaa pakettia %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Paketin %1$s varmistaminen epäonnistui, koska ohjelmistolähdettä %2$s ei "
+"löydy (%3$i ohjelmistolähteet ladattu)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Epäluotettavan tarkistaminen epäonnistui: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Ladattua tiedostoa paketille %s ei löydy"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"pakettia %1$s ei voida varmistaa ja ohjelmistolähteellä %2$s on GPG "
+"käytössä: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Arvon saaminen CacheDir:ille epäonnistui"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+"Tiedostojärjestelmän vapaan koon hakeminen hakemistolle %s epäonnistui: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+"Tiedostojärjestelmän vapaan koon hakeminen hakemistolle %s epäonnistui"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"Hakemistossa %1$s ei ole riittävästi vapaata tilaa: tarvitaan %2$s, "
+"saatavilla %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "root:in asettaminen epäonnistui"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Transaktiotestin suorittamisessa tapahtui virhe %i"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Virhe %i avattaessa rpm-tietokantaa"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "rpmdbCookie()-funktio ei palauttanut rpm-tietokannan evästettä."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Transaktion suorittamisessa tapahtui virhe %i"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"Transaktio ei mennyt kirjoitusvaiheeseen, mutta ei tuottanut virhettä (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "hakemistoa %1$s ei voi avata: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "hakemiston %s poistaminen epäonnistui"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Virheellinen valitsin, useiden osumaobjektien esiintyminen suodattimessa"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "Virheellistä valitsinta käytetään toimintoon, väärä vertailutyyppi"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s jostain %s ei kuulu tietovarastoon distupgrade"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "on huonompi arkkitehtuuri"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "ongelma tämän asennetun paketin kanssa: "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "ristiriitaiset pyynnöt"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "pyyntöä ei tueta"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "mikään ei tarjoa pyydettyä "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "pakettia %s ei ole olemassa"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " järjestelmän tarjoamana"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "riippuvuusongelma"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "ei voi asentaa paketin parasta päivitysehdokasta "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "ei voi asentaa työn parasta päivitysehdokasta"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "paketti %s jostain %s suodatetaan modulaarisella suodatuksella"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "paketilla %s jostain %s ei ole yhteensopivaa arkkitehtuuria"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "paketti %s ei ole asennettavissa"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "paketti %s jostain %s suodatetaan pois pois-suodatuksella"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "mikään ei tarjoa %s:n tarvitsemaa %s jostain %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "molempia %s ja %s ei voi asentaa"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "paketti %s on ristiriidassa %s:n tarjoamansa %s:n kanssa"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "paketti %s vanhentaa %s:n tarjoama %s:n"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "asennettu paketti %s vanhentaa %s:n tarjoama % jostain %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "paketti %s epäsuorasti vanhentaa %s:n tarjoama %s:n"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"paketti %s jostain %s vaatii %s, mutta mitään palveluntarjoajista ei voida "
+"asentaa"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "paketti %s jostain %s on ristiriidassa itse tarjoamansa %s:n kanssa"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "molemmat paketit %s ja %s vanhentavat %s:n"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s jostain %s ei kuulu tietovarastoon distupgrade"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "on huonompi arkkitehtuuri"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "ongelma asennetun moduulin kanssa "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "moduulia %s ei ole olemassa"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "ei voi asentaa parasta päivitysehdokasta moduulille "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "moduuli %s on poistettu käytöstä"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "moduulilla %s jostain %s ei ole yhteensopivaa arkkitehtuuria"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "moduuli %s ei ole asennettavissa"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "'nothing provides' %s: ta, moduulin %s jostain %s tarvitsemana"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "ei voi asentaa molempia moduuleja %s ja %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "moduuli %s on ristiriidassa %s:n tarjoamansa %s:n kanssa"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "moduuli %s vanhentaa %s:n tarjoama %s:n"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "asennettu moduuli %s vanhentaa %s:n tarjoama % jostain %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "moduuli %s epäsuorasti vanhentaa %s:n tarjoama %s:n"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"moduuli %s jostain %s vaatii %s:n, mutta yhtään palveluntarjoajista ei voida"
+" asentaa"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "moduuli %s jostain %s on ristiriidassa itse tarjoamansa %s:n kanssa"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "molemmat moduulit %s ja %s vanhentavat %s:n"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "ratkaisijaa ei ole asetettu"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "polun %s muuntaminen absoluuttiseksi epäonnistui"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+"virheenkorjaustietojen kirjoittaminen hakemistoon %1$s epäonnistui: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "ei solv:ta tavoitteessa"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "ei ratkaisua, suojattua pakettia ei voi poistaa"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "ratkaisu ei ole mahdollinen"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Ongelma: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Ongelma:%d "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Toiminto johtaisi seuraavien suojattujen pakettien poistamiseen: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+"Libsolvin solv_toolversion on: %zu pitkä, sen pitäisi olla enintään: %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Polun %1$s uudelleennimeäminen poluksi %2$s epäonnistui : %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Käyttöoikeuksien asettaminen polulle %1$s epäonnistui: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "ei voi luoda hakemistoa %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "ei voi tehdä kutsua ”stat” polkuun %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Virheellinen alustamoduulin muoto: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Saatavilla olevien pakettien tarjoamat useat moduulialustat\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Asennettujen pakettien tarjoamat useat moduulialustat\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Alustamoduulin havaitseminen tiedostosta %s epäonnistui: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "PLATFORM_ID puuttuu tiedostosta %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Kelvollista alustan tunnusta ei havaittu"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Useita virtoja moduulille ”%s” ei voi ottaa käyttöön"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Ristiriitaiset oletusasetukset ohjelmistolähteen ”%s” kanssa: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Asennetaan moduuliprofiileita:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Poistetaan käytöstä moduuliprofiileita:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Otetaan moduulivirtoja käyttöön:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Vaihdetaan moduulivirtoja:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Poistetaan moduuleita käytöstä:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Nollataan moduuleita:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+"Modulaarisen vikaturvallisen tiedon lataaminen tiedostosta ”%s” epäonnistui"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+"Modulaarisen vikaturvallisen tiedon lataaminen moduulille ”%s:%s” "
+"epäonnistui"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+"Hakemiston ”%s” luominen modulaariselle vikaturvalliselle tiedolle "
+"epäonnistui: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+"Modulaarisen vikaturvallisen tiedon tallennus tiedostoon ”%s” epäonnistui"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+"Modulaarisen vikaturvallisen tiedon poisto tiedostosta ”%s” epäonnistui"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Modulaarisia vanhentumisia ei voida soveltaa kohteisiin '%s:%s', koska "
+"kohdemoduuli '%s' on poistettu käytöstä"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Merkkijonosta päivittäminen epäonnistui: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Ratkaiseminen epäonnistui: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Modulaaristen oletusten ratkaisemisessa tapahtui virheitä: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Oletusten päivittäminen epäonnistui: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Virtojen päivittäminen epäonnistui: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr "ei voi hakea Moduulin vanhenemisia, koska virta ei täsmää %s: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Ei voi ladata jaettua kirjastoa ”%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Symbolin ”%s” osoitetta ei saada: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Ladataan liitännäistiedosto=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Ladattiin liitännäisnimi=\"%s\", versio=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath ei voi olla tyhjä"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Laajennushakemistoa ”%s” ei voi lukea: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Ei voi ladata liitännäistä ”%s”: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Ohjelmistolähteen väliaikaista hakemistoa ”%s” ei voida luoda: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Operaattorin '==' käyttö reldeps:ssä voi johtaa määrittelemättömään "
+"toimintaan. Se on vanhentunut ja tuki poistetaan tulevissa versioissa. Käytä"
+" sen sijaan operaattoria '='."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Ohjelmistolähteessä %s ei ole peiliä tai baseurl:ää asetettuna."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "Ohjelmistolähteen ”%s” tyyppiä ei tueta: ”type=%s”; ohitetaan."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "asennuslähde '%s': 'basecachedir' ei ole asetettu"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Suurin latausnopeus on pienempi kuin pienin. Muuta minrate:n tai throttle:n "
+"asetuksia"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"asennuslähde '%s': 'proxy_username' on määritetty, mutta ei 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' on määritetty, mutta ei 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Ohjelmistolähteelle ei löydy kelvollista baseurl:ia: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "GPG-avaimen noutaminen ohjelmistolähteelle ”%s” epäonnistui: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "ohjelmistolähde %s: 0x%s jo tuotu"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Hakemiston \"%s\": %d luonti epäonnistui: %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "ohjelmistolähde %s: tuotiin avain 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "elvytys: ohjelmistolähde ”%s” ohitettu, ei metalinkkiä."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+"elvytys: ohjelmistolähde ”%s” ohitettu, ei käyttökelpoista tarkistussumman "
+"tyyppiä."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+"elvytys: epäonnistui ohjelmistolähteelle ”%s”, %s-tarkistussumma ei täsmää."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"elvytys: ”%s” voidaan elvyttää - metalinkin tarkistussummat täsmäävät."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "elvytys: ”%s” voidaan elvyttää - repomd täsmää."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+"ohjelmistolähteen ”%s” elvyttäminen epäonnistui, repomd:t ovat erilaiset."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Ohjelmistolähteen kohdehakemistoa ”%s” ei voida luoda: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Hakemistoa ”%s” ei voida luoda: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Hakemistoa ”%s” ei voida nimetä uudelleen nimelle ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "käytetään välimuistia ohjelmistolähteelle %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+"Ollaan vain välimuisti -tilassa, mutta ei välimuistia ohjelmistolähteelle "
+"”%s”"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "asennuslähde: ladataan etäkohteesta: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Metatietojen lataaminen ohjelmistolähteelle ”%s” epäonnistui: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): SHA256:n laskeminen epäonnistui"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "persistdir:n ”%s” luominen epäonnistui: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"resume-toimintoa ei voi käyttää samanaikaisesti parametrin byterangestart "
+"kanssa"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTargetin alustus epäonnistui: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Ei voi avata tiedostoa %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Lokinkäsittelijää tunnuksella %ld ei ole olemassa"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Meneillään"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Ei meneillään"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Ei transaktiota meneillään"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Yritetty lisätä transaktiokohta valmiiseen transaktioon"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Yritetty päivittää transaktiokohta valmiissa transaktiossa"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Tietokanta vioittunut: taulukosta 'config' puuttuu rivi 'version'"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Muunnin: pysyvän historiakansion avaus epäonnistui"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Historiatietokantaa ei löytynyt"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Transaktio on jo alkanut!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItemin tilaa ei asetettu: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Konsolin ulostuloa ei voi lisätä tallentamattomaan transaktioon"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "avaimia ei voi luetella: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "solv:n lisääminen epäonnistui"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main():lla tietojen kirjoittaminen epäonnistui: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr ""
+#~ "write_main():lla kirjoitetun solv-tiedoston uudelleenlataaminen epäonnistui"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) epäonnistui %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() epäonnistui."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Moduuliartefakti NEVRA:n jäsentäminen epäonnistui: '%s'"
--- /dev/null
+# Alvin Abuke <abuke.ac@gmail.com>, 2018. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2018-04-12 04:47+0000\n"
+"Last-Translator: Alvin Abuke <abuke.ac@gmail.com>\n"
+"Language-Team: Filipino\n"
+"Language: fil\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n > 1\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Hindi mahagilap ang wastong baseurl para sa repo: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Jean-Baptiste Holcroft <jean-baptiste@holcroft.fr>, 2016. #zanata, 2021.
+# José Fournier <jaaf64@zoraldia.com>, 2016. #zanata
+# José Fournier <jaaf64@zoraldia.com>, 2017. #zanata
+# Jérôme Fenal <jfenal@gmail.com>, 2017. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata, 2021, 2022.
+# Jean-Baptiste Holcroft <jean-baptiste@holcroft.fr>, 2019. #zanata, 2021.
+# Julien Humbert <julroy67@gmail.com>, 2020, 2021.
+# Arnaud T. <listes.00@gmail.com>, 2020.
+# Sundeep Anand <suanand@redhat.com>, 2021, 2022.
+# Titouan Bénard <itotutona@evta.fr>, 2021.
+# Arthur Tavernier <arthur.tavernier45@gmail.com>, 2022.
+# blutch112 <vincent.lefebvre59@gmail.com>, 2022.
+# Transtats <suanand@redhat.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-03-07 14:20+0000\n"
+"Last-Translator: Transtats <suanand@redhat.com>\n"
+"Language-Team: French <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/fr/>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "aucune valeur n’est indiquée"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "la valeur en secondes « %s » ne doit pas être négative"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "n’a pu convertir « %s » en octets"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unité « %s » inconnue"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "valeur non valide"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "la valeur 1 n’est pas autorisée"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "la valeur négative n'est pas autorisée"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "le pourcentage « %s » est en dehors des limites"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configuration : OptionBinding ayant pour id « %s » n’existe pas"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configuration : OptionBinding ayant pour « %s » n’existe pas"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valeur booléenne invalide : « %s »"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "la valeur « %s » n’est pas autorisée"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "la valeur fournie [%d] doit être inférieure à la valeur permise [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "la valeur fournie [%d] doit être supérieure à la valeur permise [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "le chemin fourni « %s » n’est pas absolu."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "le chemin fourni « %s » n’existe pas."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "n’a pu convertir « %s » en secondes"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue() : valeur non définie"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Ne peut pas activer plus de flux du module '%s' en même temps"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Impossible d'activer le flux de module '%1$s' stream '%2$s' : état du module"
+" déjà modifié"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Problème de dépendance modulaire avec les valeurs par défaut : %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Problème de dépendance modulaire avec les derniers modules : %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Problème de dépendance modulaire : %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Impossible de résoudre le paramètre ’%s’"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Seul le nom du module est nécessaire. Les paramètres inutiles ont été "
+"ignorés : ’%s’"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"Impossible de réinitialiser le module '%s' : État du module déjà modifié"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Impossible de désactiver le module '%s' : État du module déjà modifié"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Aucune donnée modulaire disponible"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ignorer les informations inutiles dans l'argumentation : '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Problème lors de l'activation de l'arbre des dépendances pour le module "
+"'%1$s' flux '%2$s' : %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Des problèmes sont apparus pour la demande d'activation du module :"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+"Aucun paquetage de module actif n'a été trouvé pour le module spec '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Impossible d'installer le module '%s' à partir du dépôt de sécurité"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Aucun profil trouvé correspondant à '%s'"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Aucune correspondance pour le paquet '%s' pour le module spec %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Problème lors de l'installation du module '%1$s' stream '%2$s' : %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Des problèmes sont apparus pour la demande d'installation du module :"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+"Des problèmes sont apparus pour la demande de réinitialisation des modules :"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+"Des problèmes sont apparus pour la demande de désactivation du module :"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Le résultat de l’opération sera le basculement du flux « %s » du module « %s"
+" » vers le flux « %s »"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Il n’est pas possible de basculer les flux actifs d’un module. \n"
+"Il est recommandé de retirer tout contenu installé par le module, et de réinitialiser le mode en utilisant la commande 'microdnf module reset <module_name>’. Après la réinitialisation du module, vous pouvez installer les autres flux."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Impossible de depsolve la transaction ; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i problème détecté :\n"
+msgstr[1] "%i problèmes détectés :\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problème %1$i : %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problème : %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Aucune métadonnée modulaire n’est disponible pour le paquet modulaire "
+"« %s » ; impossible d’installer le paquet sur le système"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "signature ne correspondant pas pour %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "n’a pas pu ouvrir(erreur générique) : %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "n’a pas pu vérifier la clé pour %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "clé publique non disponible pour %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "signature non trouvée pour %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "n’a pas pu ajouter l’élément : %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Erreur d’exécution pour la transaction : %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "Erreur d’exécution de la transaction et pas de problème reporté !"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Erreur fatale, exécuter le recouvrement de la base de données"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "n’a pas pu trouver le package %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "n’a pas pu ajouter d’élément pour effacer %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() a échoué."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Le chargement du cache d'extension %s (%d) a échoué : "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "aucune chaine %1$s pour %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "n’a pas pu ouvrir : %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "n’a pas pu créer le fichier temporaire : %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "n’a pas pu ouvrir le fichier tmp : %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Lors de l'écriture dans le cache primaire %s, l'écriture dans le repowriter "
+"a échoué : %i, erreur : %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Échec de la fermeture du fichier tmp %s : %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Échec de l'utilisation du cache primaire nouvellement écrit : %s : "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Échec de l'utilisation du cache primaire nouvellement écrit : %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "n’a pas pu créer le fichier temporaire %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Lors de l'écriture du cache d'extension %s (%d) : écriture repowriter ayant "
+"échoué : %i, erreur : %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"Lors de l'écriture du cache d'extension (%d) : impossible de fermer le "
+"fichier temporaire : %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Impossible d'utiliser le nouveau cache d'extension écrit : %s (%d) : "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Impossible d'utiliser le nouveau cache d'extension écrit : %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "fichier md de dépôt nul"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "n’a pu lire le fichier %1$s : %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Lors du chargement du référentiel, l'utilisation de %s a échoué : "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "échec du chargement du MD_TYPE_PRIMARY."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "L'ouverture des données primaires du référentiel a échoué : %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Le chargement de repomd a échoué : %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Le chargement du primaire a échoué : %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "n’a pu auto-détecter l’architecture"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "n’a pu créer le cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "n’a pu télécharger RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Aucun module par défaut n’a été trouvé : %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "pourcentage pas à 100 : %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "n’a pas pu définir le nombre d’étapes : %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "annulé par action de l’utilisateur"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "effectué sur un état %1$p qui n’avait pas de taille définie [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "déjà en état à 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Sources non définies quand vous essayez d’assurer paquet %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "N’a pu assurer %1$s comme dépôt %2$s non trouvé (%3$i dépôts chargés)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Échec de la vérification d’untrusted : "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Fichier téléchargé pour %s non trouvé"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"le paquet %1$s ne peut être vérifié et le dépôt %2$s est activé GPG : %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "N’a pas pu obtenir la valeur de CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+"Échec de l’obtention de l’espace libre du système de fichiers pour %s : "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "N’a pas pu obtenir la taille libre du système de fichiers pour %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"Pas suffisamment d’espace libre dans %1$s : a besoin de %2$s, disponible "
+"%3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "n’a pu réussi à définir root"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Erreur %i lors du test transactionnel"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Erreur %i lors de l’ouverture de la base de données rpm"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+"La fonction rpmdbCookie() n'a pas retourné le cookie de la base de données "
+"rpm."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Erreur %i pendant la transaction"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"La transaction n’a pas pu opérer en phase d’écriture, mais a renvoyé « no "
+"error(%i) »"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "impossible d’ouvrir le dossier %1$s : %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "n’a pas pu supprimer %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Sélecteur Ill-formed, présence de plusieurs objets correspondants dans le "
+"filtre"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Sélecteur Ill-formed utilisé pour l’opération, type de comparaison "
+"incorrecte"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "n’appartient pas à un dépôt distupgrade"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "a une architecture inférieure"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problème avec le paquet installé "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "requêtes conflictuelles"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "requête non prise en charge"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "rien ne fourni ce qui a été demandé "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "le paquet %s n’existe pas"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " est fourni par le système"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "quelques problèmes de dépendances"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "installation impossible du meilleur candidat pour le paquet "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "installation impossible du meilleur candidat pour la tâche"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "le paquet %s a été filtré par filtrage modulaire"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "le paquet %s n’a pas d’architecture compatible"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "le paquet %s n’est pas installable"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "le paquet %s a été filtré en excluant le filtrage"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "rien de fournit %s rendu nécessaire par %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "installation impossible à la fois de %s et %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "le paquet %s est en conflit avec %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "le paquet %s rend obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "le paquet installé %s rend obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "le paquet %s rend implicitement obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"le paquet %s nécessite %s, mais aucun fournisseur ne peut être installé"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "le paquet %s est en conflit avec %s fourni par lui-même"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "à la fois le paquet %s et %s rendent obsolète %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "n’appartient pas à un dépôt distupgrade"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "a une architecture inférieure"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "problème avec le module installé "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "le module %s n’existe pas"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+"installation impossible du meilleur candidat de mise à jour pour le module "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "le module %s est désactivé"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "le module %s n’a pas d’architecture compatible"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "le module %s n’est pas installable"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "rien de fournit %s rendu nécessaire par le module %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "installation impossible à la fois des modules %s et %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "le module %s est en conflit avec %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "le module %s rend obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "le module installé %s rend obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "le module %s rend implicitement obsolète %s fourni par %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"le module %s nécessite %s, mais aucun fournisseur ne peut être installé"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "le module %s est en conflit avec %s fourni par lui-même"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "à la fois le module %s et %s rendent obsolète %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "aucun solveur défini"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "n’a pas pu rendre %s absolu"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "échec de l’écriture des debugdata dans %1$s : %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "pas de solv dans l’objectif"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "aucune solution, n’a pas pu supprimer le package protégé"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "aucune solution n’est possible"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Problème : "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Probléme %d : "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+"L’opération résulterait en la suppression des packages protégés suivants : "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+"La solv_toolversion de Libsolv est : %zu long mais nous attendons un maximum"
+" de : %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "N’a pas pu renommer %1$s en %2$s : %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "N’a pas pu définir les permissions sur %1$s : %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "impossible de créer le dossier %1$s : %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "impossible de stat le chemin %1$s : %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Format invalide du module de plateforme : %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+"De multiples modules de plateformes sont fournis par les paquets "
+"disponibles\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+"De multiples modules de plateformes sont fournis par les paquets installés\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "La détection des modules de plateformes dans %s a échoué : %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "L'identifiant de la platforme est manquant dans %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Aucun identifiant de plateforme n'a été détecté"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Impossible d’activer les flux pour le module « %s »"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Valeurs par défaut en conflit avec le dépôt « %s » : %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Installation des profils de module :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Désactivation des profils de module :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Activation des flux de modules :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Basculement des flux de modules :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Désactivation des modules :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Réinitialisation des modules :\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Impossible de charger les données de sécurité à « %s »"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+"Impossible de charger les données de sécurité modulaires pour le module "
+"« %s : %s »"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+"Impossible de créer le dossier « %s » pour les données de sécurité "
+"modulaires : %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+"Impossible d’enregistrer les données de sécurité modulaires vers « %s »"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+"Impossible de supprimer les données de sécurité modulaires dans « %s »"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Impossible d'appliquer les obsolètes modulaires à '%s:%s' car le module "
+"cible '%s' est désactivé"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Échec de la mise à jour depuis la chaine : %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Échec de la résolution : %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+"Il y a eu des erreurs lors de la résolution des modulaires par défaut : %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Échec de la mise à jour des paramètres par défaut : %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Échec de la mise à jour des flux : %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"Impossible de récupérer les modules obsolètes car aucune correspondance de "
+"flux %s : %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Impossible de charger la librairie partagé « %s » : %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Impossible d’obtenir l’adresse du symbole « %s » : %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Chargement du fichier d’extension fichier=« %s »"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Extension chargée, nom=« %s », version=« %s »"
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+"Le chemin du dossier (dirPath) Plugins::loadPlugins() ne peut pas être vide"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Impossible de lire de dossier de l’extension « %s » : %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Impossible de charger l’extension « %s » : %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Impossible de créer le répertoire temporaire du dépôt « %s » : %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"L’utilisation de l’opérateur « == » dans reldeps peut entraîner un "
+"comportement indéfini. Il est déprécié et le support sera abandonné dans les"
+" prochaines versions. Utilisez plutôt l’opérateur « = »."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Le dépôt %s n’a pas de miroir ou d’adresse de base."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+"Le dépôt « %s » n’a pas de type pris en charge : « type=%s », passer outre."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "repo '%s' : 'basecachedir' n'est pas fixé"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"La vitesse de téléchargement maximale est plus basse que le minimum. "
+"Veuillez modifier les paramètres minrate ou throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "repo '%s' : 'proxy_username' est défini mais pas 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"Le nom d'utilisateur \"proxy_username\" est défini mais pas le mot de passe "
+"\"proxy_password\""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Impossible de trouver une adresse de base pour le dépôt : %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Impossible de récupérer la clé GPG pour le dépôt « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "dépôt %s : 0x%s déjà importé"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Impossible de créer le répertoire \"%s« :%d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "dépôt %s : clé importée 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "relance : dépôt « %s » ignoré, pas de méta-lien."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "relance : dépôt « %s » ignoré, pas de hachage utilisable."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "relance : échec pour « %s », la somme de %s ne correspond pas."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"relance : « %s » peut être relancé - la somme de contrôle du méta-lien "
+"correspond."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "relance : « %s » peut être relancé - le repomd correspond."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "relance : échec pour « %s », le repomd ne correspond pas."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Impossible de créer le répertoire de destination du dépôt « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Impossible de créer le répertoire « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Impossible de renommer le répertoire « %s » en « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "dépôt : utilisation du cache pour : %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "« cache uniquement » activé, mais pas de cache pour « %s »"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "dépôt : téléchargement à distance en provenance de : %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Échec du téléchargement des métadonnées pour le dépôt « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir() : échec du calcul de SHA256"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Impossible de créer le dossier persistant « %s » : %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"« resume » (reprise) ne peut pas être utilisé avec le paramètre "
+"byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "L’initialisation de Package Target a échoué : %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "impossible d’ouvrir %s : %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Log handler ayant pour id %ld n’existe pas"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "En cours"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Pas en cours"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Aucune transaction n’est en cours"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+"Tentative d’insérer un élément de transaction dans une transaction achevée"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+"Tentative de mettre à jour un élément de transaction dans une transaction "
+"achevée"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+"Base de données corrompue : ligne « version » manquante dans le tableau "
+"« config »"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+"Transformer : n’a pu ouvrir le répertoire de persistance de l’historique"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "N’a pas pu trouver de base de données de l’historique"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "La transaction a déjà commencé !"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "L’état du TransactionItem n’est pas défini : %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+"Ne peut pas ajouter une sortie de console à une transaction non enregistrée"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s : gpgme_data_new_from_fd() : %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s : gpgme_op_import() : %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s : gpgme_ctx_set_engine_info() : %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "n’a pas pu lister les clés : %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "n’a pu ajouter solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() n’a pu écrire les données : %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() n’a pas pu charger à nouveau le fichier solv"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) a échoué : %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() a échoué."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Échec de l’analyse du module d’artéfact NEVRA : %s"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "ID erroné pour le dépôt : %s, byte = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "n’a pu calculer la somme de contrôle RPMDB"
--- /dev/null
+# Fabio Tomat <f.t.public@gmail.com>, 2018. #zanata, 2020, 2021, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-03-05 05:24+0000\n"
+"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
+"Language-Team: Friulian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/fur/>\n"
+"Language: fur\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nissun valôr specificât"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "il valôr dai seconts '%s' nol à di jessi negatîf"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "no ai podût convertî '%s' in bytes"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unitât '%s' no cognossude"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "valôr no valit"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "il valôr 1 nol è ametût"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "nol è consintût un valôr negatîf"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "la percentuâl '%s' e je fûr di scjale"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configurazion: OptionBinding cun id \"%s\" nol esist"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configurazion: OptionBinding cun id \"%s\" al esist bielzà"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valôr boolean '%s' no valit"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' nol è un valôr permetût"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "il valôr furnît [%d] al à di jessi minôr dal valôr permetût [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+"il valôr furnît [%d] al à di jessi plui grant dal valôr permetût [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "il percors furnît '%s' nol è assolût."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "il percors furnît '%s' nol esist."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "no ai podût convertî '%s' in seconts"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): valôr no stabilît"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Impussibil abilitâ altris flus dal modul '%s' tal stes timp"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Impussibil abilitâ il flus '%2$s' dal modul '%1$s': stât dal modul za "
+"modificât"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Probleme di dipendence modulâr cui predefinîts: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Probleme di dipendence modulâr cui ultins modui: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Probleme di dipendence modulâr: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Impussibil risolvi l'argoment '%s'"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Al covente dome il non dal modul. Si ignore lis informazions tal argoment "
+"che no coventin: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"Impussibil tornâ a inizializâ il modul '%s': stât dal modul za modificât"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Impussibil disabilitâ il modul '%s': stât dal modul za modificât"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Nissun dât modulâr disponibil"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Daûr a ignorâ lis informazions tal argoment che no coventin: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Probleme dilunc la abilitazion dal arbul des dipendencis pal flus '%2$s' dal"
+" modul '%1$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Problemis vignûts fûr pe richieste di abilitazion dal modul:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Nissun pachet dal modul atîf cjatât pal modul spec '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+"Impussibil instalâ il modul '%s' dal dipuesit \"fail-safe\" (a prove di "
+"erôrs)"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Nissun profîl cjatât corispondent a '%s'"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Nissune corispondence pal pachet '%s' pal modul spec %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Probleme dilunc la instalazion pal flus '%2$s' dal modul '%1$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "A son vignûts fûr problemis pe richieste di instalazion dal modul:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "A son vignûts fûr problemis pe richieste di azerament dal modul:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "A son vignûts fûr problemis pe richieste di disabilitazion dal modul:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"La operazion e puartarà tal modul '%s' il passaç dal flus '%s' al flus '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Nol è pussibil passâ ai flus abilitâts di un modul.\n"
+"Si consee di gjavâ dal modul ducj i contignûts instalâts e azerâ il modul doprant il comant 'microdnf module reset <non_modul>'. Dopo vê azerât il modul, tu puedis instalâ l'altri flus."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Impussibil il depsolve de transazion; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i probleme rilevât:\n"
+msgstr[1] "%i problemis rilevâts:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Probleme %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Probleme: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Nissun metadât modulâr disponibil pal pachet modulâr '%s'; impussibil "
+"instalâ il pachet sul sisteme"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "la firme no cuadre par %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "impussibil vierzi (erôr gjeneric): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "impussibil verificâ la clâf par %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "clâf publiche no disponibile par %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "no si à cjatât la firme par %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "impussibil zontâ l'element di instalazion %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Erôr dilunc la esecuzion de transazion: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Erôr dilunc la esecuzion de transazion e no son stât segnalâts problemis!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Erôr fatâl, eseguî il ripristinament de base di dâts"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "nol è stât pussibil cjatâ il pachet %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "impussibil zontâ un element di cancelazion %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() al à falât."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Cjariament de cache de estension %s (%d) falît: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "nissune stringhe %1$s par %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "nol è stât pussibil vierzi: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "nol è stât pussibil creâ un file temporani: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "nol è stât pussibil vierzi il file tmp: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Dilunc la scriture de cache primarie %s la scriure di repowriter e je "
+"falide: %i, erôr %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Nol è stât pussibil sierâ il file tmp %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Nol è stât pussibil doprâ la cache primarie a pene scrite: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Nol è stât pussibil doprâ la cache primarie a pene scrite: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "nol è pussibil creâ il file temporani %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo md file"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "impussibil lei il file %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "nol è stât pussibil cjariâ MD_TYPE_PRIMARY."
+
+#: libdnf/dnf-sack.cpp:784
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Opening repository primary data has failed: %s"
+msgstr "Daûr a cjariâ il file dal plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:795
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading repomd has failed: %s"
+msgstr "Daûr a cjariâ il file dal plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:806
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading primary has failed: %s"
+msgstr "Daûr a cjariâ il file dal plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "nol è stât pussibil rilevâ in automatic la architeture"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "nol è stât pussibil creâ la cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "nol è stât pussibil cjariâ la RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "percentuâl no a 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "impussibil stabilî i passaçs numerics: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "anulât de azion dal utent"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "fat suntun stât %1$p che nol veve une dimension stabilide! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "za al stât di 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Sorzints no stabilidis cuant che si cîr di garantî il pachet %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Nol è stât pussibil garantî %1$s tant che dipuesit %2$s no cjatât (%3$i "
+"dipuesits cjariâts)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Impussibil verificâ la mancjance di fidance: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "File discjariât par %s no cjatât"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"nol è pussibil verificâ il pachet %1$s e il dipuesit %2$s al è abilitât par "
+"GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Impussibil otignî il valôr par CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Impussibil otignî la grandece dal spazi libar sul filesystem par %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Impussibil otignî la grandece dal spazi libar sul filesystem par %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "No vonde spazi libar su %1$s: a coventin %2$s, disponibii %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "impussibil stabilî la lidrîs"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Erôr %i eseguint la prove de transazion"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Erôr %i eseguint la transazion"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"La transazion no je lade ae fase di scriture, ma no à tornât indaûr nissun "
+"erôr (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "impussibil vierzi la cartele %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "nol è stât pussibil gjavâ %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "Seletôr malformât, presince di plui ogjets corispondents tal filtri"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "Seletôr malformât doprât pe operazion, gjenar di confront sbaliât"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "nol aparten a un dipuesit di avanzament di distribuzion"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "al à une architeture inferiôr"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "probleme cul pachet instalât "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "richiestis in conflit"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "richieste no supuartade"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "nie al furnìs ce che si à domandât "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "il pachet %s nol esist"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " al è furnît dal sisteme"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "cualchi probleme di dipendence"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "impussibil instalâ il miôr candidât di inzornament pal pachet "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "impussibil instalâ il miôr candidât pal lavôr"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "il pachet %s al è stât filtrât de filtradure modulâr"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "il pachet %s nol à une architeture compatibile"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "il pachet %s nol è instalabil"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "il pachet %s al è filtrâ de filtradure di esclusion"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "nie al furnìs %s necessari par %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "impussibil instalâ ducj i doi %s e %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "il pachet %s al va in conflit cun %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "il pachet %s al rint sorpassât %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "il pachet instalât %s al rint sorpassât %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"il pachet %s al rint sorpassât in maniere implicite %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"il pachet %s al à bisugne di %s, ma nol è pussibil instalâ nissun furnidôr"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "il pachet %s al va in conflit cun %s che al è furnît di se stes"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "ducj i doi i pachets %s e %s a rindin sorpassât %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "nol aparten a un dipuesit di avanzament di distribuzion"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "al à une architeture inferiôr"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "probleme cul modul instalât "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "il modul %s nol esist"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "Impussibil instalâ il miôr candidât pal inzornament dal modul "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "il modul %s al è disabilitât"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "il modul %s nol à une architeture compatibile"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "il modul %s nol è instalabil"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "nie al furnìs %s che al covente al modul %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "impussibil instalâ ducj i doi i modui %s e %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "il modul %s al va in conflit cun %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "il modul %s al rint sorpassât %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "il modul instalât %s al rint sorpassât %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"il modul %s al rint sorpassât in maniere implicite %s che al è furnît di %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"il module %s al à bisugne di %s, ma no si pues instalâ nissun dai furnidôrs"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "il modul %s al va in conflit cun %s che al è furnît di se stes"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "ducj i doi i modui %s e %s a rindin sorpassât %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "nissun risolutôr stabilît"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "nol è stât pussibil rindi assolût %s"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "nol è stât pussibil scrivi i dâts di debug (debugdata) su %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "nissun solv tal obietîf"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "nissune soluzion, impussibil gjavâ il pachet protet"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "nissune soluzion pussibile"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "La operazion e puartarà a une rimozion di chescj pachets protets: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Nol è stât pussibil cambiâ il non di %1$s a %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Nol è stât pussibil stabilî i permès su %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "impussibil creâ la cartele %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "impussibil eseguî il \"stat\" dal percors %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Formât no valit dal modul de plateforme: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Furnidis, dai pachets disponibii, multiplis plateformis di modul\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Furnidis, dai pachets instalâts, multiplis plateformis di modul\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Rilevament falît dal modul di plateforme in %s: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "In %s al mancje PLATFORM_ID"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Nissun ID di plateforme valit rilevât"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Impussibil abilitâ flus multiplis pal modul '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Valôrs predefinîts in conflit cul dipuesit '%s': %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+"Impussibil cjariâ i dâts a prove di erôrs (fail-safe) modulârs su '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+"Impussibil cjariâ i dâts a prove di erôrs (fail-safe) modulârs pal modul "
+"'%s:%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Impussibil creâ la cartele \"%s\" pai dâts modulârs a prove di erôr: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Impussibil salvâ un dât modulâr a prove di erôr su '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Impussibil gjavâ un dât modulâr a prove di erôr in '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Nol è stât pussibil inzornâ de stringhe: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Nol è stât pussibil risolvi: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Nol è stât pussibil inzornâ i parametris predefinîts: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Nol è stât pussibil inzornâ i flus: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Impussibil cjariâ la librarie condividude \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Impussibil otignî la direzion dal simbul \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Daûr a cjariâ il file dal plugin=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Daûr a cjariâ il non dal plugin=\"%s\", version=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+"Il percors de cartele dirPath di Plugins::loadPlugins() nol pues jessi "
+"vueit"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Impussibil lei la cartele dal plugin \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Impussibil cjariâ il plugin \"%s\": %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Impussibil creâ la cartele temporanie dal dipuesit \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Il dipuesit %s nol à stabilît nissun servidôr-spieli o url di base."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "Il dipuesit '%s' al à un gjenar no supuartât: 'type=%s', si salte."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"La velocitât massime e je minôr di chê minime. Si pree di cambiâ la "
+"configurazion di minrate o di throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Impussibil cjatâ un url di base valit pal repo: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Nol è stât pussibil recuperâ la clâf GPG pal dipuesit '%s': %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "dipuesit %s: 0x%s za impuartât"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, fuzzy, c-format
+#| msgid "Cannot create directory \"%s\": %s"
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Impussibil creâ la cartele \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "dipuesit %s: clâf 0x%s impuartade."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "riativazion: dipuesit '%s' saltât, nissun meta-colegament."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "riativazion: dipuesit '%s' saltât, nissun hash che si pues doprâ."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+"riativazion: no je stade pussibile par '%s', la sume di control %s no "
+"corispuint."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"riativazion: al è pussibil riativâ '%s' - la sume di control dal meta-"
+"colegament e corispuint."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+"riativazion: al è pussibil riativâ '%s' - il file repomd al corispuint."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+"riativazion: no je stade pussibile par '%s', il file repomd nol corispuint."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Impussibil creâ la cartele di destinazion dal dipuesit \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Impussibil creâ la cartele \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Impussibil cambiâ non de cartele \"%s\" in \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "dipuesit: daûr a doprâ la cache par %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Modalitât dome-cache abilitade, ma no esist nissune cache par '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "dipuesit: discjariament di lontan: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Nol è stât pussibil discjariâ i metadâts pal dipuesit '%s': %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): calcul di SHA256 falît"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Impussibil creâ la cartele persistente (persostdir) \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"nol è pussibil doprâ “resume” in maniere contemporanie cul parametri "
+"byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Inizializazion di PackageTarget falide: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Impussibil vierzi %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Il gjestôr dal regjistri cun ID %ld nol esist"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "In cors"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "No in cors"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Nissune transazion in cors"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Tentatîf di inserî l'ogjet de transazion te transazion completade"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Tentatîf di inzornâ l'element de transazion te transazion completade"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: impussibil vierzi la cartele persistente dal storic"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Impussibil cjatâ une base di dâts dal storic"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "La transazion e je za scomençade!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Il stât di TransactionItem nol è stabilît: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Impussibil zontâ la jessude de console ae transazion no salvade"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "no pues listâ lis clâfs: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "nol è stât pussibil zontâ solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main () nol è rivât a scrivi i dâts: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main () nol è rivât a tornâ a cjariâ il file solv scrit"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) al à falât: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() al à falât."
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:13+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Gujarati\n"
+"Language: gu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "પ્રગતિમાં છે"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:19+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Hindi\n"
+"Language: hi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "प्रगति में"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Meskó Balázs <meskobalazs@gmail.com>, 2016. #zanata
+# Meskó Balázs <meskobalazs@gmail.com>, 2017. #zanata
+# Teknős Ferenc <teknos.ferenc@gmail.com>, 2018. #zanata
+# Balázs Meskó <meskobalazs@mailbox.org>, 2020, 2021, 2022.
+# Dankaházi (ifj.) István <dankahazi.istvan@gmail.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-05-10 19:21+0000\n"
+"Last-Translator: Dankaházi (ifj.) István <dankahazi.istvan@gmail.com>\n"
+"Language-Team: Hungarian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/hu/>\n"
+"Language: hu\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nincs érték megadva"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "a(z) „%s” másodperc érték nem lehet negatív"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "a(z) „%s” nem alakítható bájtokká"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "ismeretlen egység: „%s”"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "érvénytelen érték"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "az 1-es érték nem megengedett"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "a negatív érték nem megengedett"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "a(z) „%s” százalék a tartományon kívül esik"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Konfiguráció: a(z) „%s” azonosítójú OptionBinding nem létezik"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Konfiguráció: a(z) „%s” azonosítójú OptionBinding már létezik"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "érvénytelen logikai érték: „%s”"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "a(z) „%s” érték nem megengedett"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+"a megadott értéknek [%d] kisebbnek kell lennie, mint a megengedett érték "
+"[%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+"a megadott értéknek [%d] nagyobbnak kell lennie, mint a megengedett érték "
+"[%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "a megadott „%s” útvonal nem abszolút."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "a megadott „%s” útvonal nem létezik."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "a(z) „%s” nem alakítható másodpercekké"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Nincs érték megadva"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Nem engedélyezhető egyszerre több forrás a(z) „%s” modulból"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Nem engedélyezhető a(z) „%1$s” modul „%2$s” forrása: A modul állapota már "
+"módosítva lett"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Moduláris függőségi probléma a legfrissebb modulokkal: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Moduláris függőségi probléma: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Nem lehet feloldani a(z) „%s” argumentumot"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Csak a modulnév szükséges. A szükségtelen információ figyelmen kívül hagyása"
+" az argumentumban: „%s”."
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"A(z) „%s” modul nem állítható alaphelyzetbe: A modul állapota már módosítva "
+"lett"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "A(z) „%s” modul nem tiltható le: A modul állapota már módosítva lett"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "A moduláris adatok nem érhetők el"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+"A szükségtelen információ figyelmen kívül hagyása az argumentumban: „%s”"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Probléma a(z) „%1$s” modul „%2$s” forrásának függőségi fájának engedélyezése"
+" során: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Probléma történt a modul engedélyezési kérése során:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Nem található aktív modulcsomag a(z) „%s” modulspecifikációhoz"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Nem telepíthető a(z) „%s” modul az üzembiztos tárolóból"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Nem található a következőnek megfelelő profil: „%s”"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Nem található a(z) „%s” csomag a(z) „%s” modulspecifikációhoz"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Probléma a(z) „%1$s” modul „%2$s” forrásának telepítése során: %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Probléma történt a modul telepítési kérése során:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Probléma történt a modul alaphelyzetbe állítási kérése során:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Probléma történt a modul letiltási kérése során:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"A művelet azt eredményezné, hogy a(z) „%s” modul a(z) „%s” forrásról a(z) "
+"„%s” forrásra váltson"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"A modulok engedélyezett forrásainak átváltása nem lehetséges.\n"
+"Ajánlatos eltávolítani a modul összes telepített tartalmát, és alaphelyzetbe állítani a modult a „dnf module reset <modulnév>” paranccsal. Ha alaphelyzetbe állította a modult, akkor telepítheti a másik forrást."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "A tranzakció függőségei nem oldhatók fel; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i probléma észlelve.\n"
+msgstr[1] "%i probléma észlelve.\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " %1$i. probléma: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Probléma: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"A moduláris metaadatok nem érhetőek el a(z) „%s” moduláris csomaghoz, ezért "
+"nem telepíthető a rendszerre"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "az aláírás nem felel meg ennél: %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "a megnyitás sikertelen (általános hiba): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "a(z) %s kulcsának ellenőrzése sikertelen"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "a(z) %s nyilvános kulcsa nem érhető el"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "a(z) %s aláírása nem található"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "a telepítendő elem hozzáadása sikertelen: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Hiba a tranzakció futtatásakor: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Hiba a tranzakció futtatásakor, és semmilyen probléma nem volt jelentve!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Végzetes hiba, adatbázis-helyreállítás futtatása"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "a(z) %s csomag nem található"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "a törlendő elem nem adható hozzá: %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "a repo_add_solv() sikertelen."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "A bővítmény %s gyorsítótárának (%d) betöltése sikertelen: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "nincs %1$s karakterlánc ehhez: %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "megnyitás sikertelen: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "nem hozható létre ideiglenes fájl: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "az átmeneti fájl megnyitása sikertelen: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"A(z) %s elsődleges gyorsítótár írása során a repowriter írása sikertelen: "
+"%i, hiba: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "A(z) %s átmeneti fájl bezárása sikertelen: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "A frissen írt elsődleges gyorsítótár használata sikertelen: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "A frissen írt elsődleges gyorsítótár használata sikertelen: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "nem hozható létre a(z) %s ideiglenes fájl"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null tároló MD-fájl"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "a(z) %1$s fájl nem írható: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "az MD_TYPE_PRIMARY betöltése sikertelen."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "az architektúra automatikus észlelése sikertelen"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "a(z) %s gyorsítótármappa létrehozása sikertelen"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "az RPMDB betöltése sikertelen"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "a lépésszám beállítása sikertelen: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "felhasználó által megszakítva"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "Az rpmdbCookie() függvény nem adta vissza az rpm adatbázis sütijét."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "ütköző kérések"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "nem támogatott kérés"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "semmi sem biztosítja amit kért "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "a(z) %s csomag nem létezik"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " a rendszer által biztosított"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "valamilyen függőségi probléma"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "a %s csomag %s-ből nem telepíthető"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "semmi sem biztosít %s-t, amelyre %s szüksége van %s-tól"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "Cannot install module '%s' from fail-safe repository"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "Nem telepíthető a(z) „%s” modul az üzembiztos tárolóból"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "a(z) %s csomag nem telepíthető"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "Cannot install module '%s' from fail-safe repository"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "Nem telepíthető a(z) „%s” modul az üzembiztos tárolóból"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "nincs megoldó beállítva"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "nincs megoldás, a védett csomag nem távolítható el"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "nincs megoldás"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Probléma: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Probléma %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "A művelet a következő védett csomagok eltávolítását eredményezné: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Modulprofilok telepítése:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Modulprofilok letiltása:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Modulforrások engedélyezése:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Modulforrások váltása:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Modulok letiltása:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Modulok alaphelyzetbe állítása:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "A(z) „%s” tárolóhoz nincs tükör vagy bázis-URL beállítva."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"A legnagyobb letöltési sebesség alacsonyabb mint a legkisebb. Módosítsa a "
+"minimális sebesség vagy a korlátozás beállítását"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Nem található érvényes bázis-URL a tárolóhoz: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "%s tároló: a 0x%s már importálva lett"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Nem hozható létre a(z) „%s” könyvtár: %d – %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "%s tároló: 0x%s kulcs importálva."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "újraélesztés: „%s” tároló kihagyva, nincs metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "újraélesztés: „%s” tároló kihagyva, nincs használható hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "újraélesztés: „%s” esetén sikertelen, nem egyező %s összeg."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"újraélesztés: „%s” újraéleszthető – a metalink ellenőrzőösszegek egyeznek."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "újraélesztés: „%s” újraéleszthető – a repomd egyezik."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "újraélesztés: „%s” esetén sikertelen, nem egyező repomd."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Nem hozható létre a(z) „%s” könyvtár: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "tároló: gyorsítótár használata a következőhöz: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+"Csak gyorsítótárazás engedélyezve, de nincs gyorsítótár a(z) „%s” tárolóhoz"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): A SHA256 kiszámítása sikertelen"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Nem hozható létre a(z) „%s” állandó könyvtár: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "A PackageTarget előkészítése sikertelen: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "A(z) %s nem nyitható meg: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "A(z) %ld azonosítójú naplókezelő nem létezik"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Folyamatban"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Nincs folyamatban"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Nincs folyamatban tranzakció"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+
+#~ msgid "failed to add solv"
+#~ msgstr "a megoldás hozzáadása sikertelen"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "a write_main() nem tudta kiírni az adatokat: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "a write_main() nem tudta újratölteni a kiírt megoldásfájlt"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "a write_ext(%1$d) sikertelen: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "a repo_add_repomdxml/rpmmd() sikertelen."
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Hibás tárolóazonosító: %s, bájt = %s %d"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:26+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Interlingua\n"
+"Language: ia\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "In curso"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Syahmin Sukhairi <syahmin@gmail.com>, 2020.
+# Andika Triwidada <andika@gmail.com>, 2020, 2022.
+# Didik Supriadi <didiksupriadi41@gmail.com>, 2021.
+# Alief Gilang <aliefgilang54@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2022-03-27 13:32+0000\n"
+"Last-Translator: Andika Triwidada <andika@gmail.com>\n"
+"Language-Team: Indonesian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/id/>\n"
+"Language: id\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.11.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "tidak ada nilai yang ditentukan"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "tidak dapat mengubah '%s' menjadi byte"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unit '%s' tidak diketahui"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "nilai tidak valid"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "nilai 1 tidak diperbolehkan"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "nilai negatif tidak diperbolehkan"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "persentase '%s' di luar batas"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Konfigurasi: OptionBinding dengan id \"%s\" tidak ada"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Konfigurasi: OptionBinding dengan id \"%s\" sudah ada"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "nilai boolean tidak valid '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, fuzzy, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' bukan nilai yang diizinkan"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "tidak dapat mengkonversi '%s' ke detik"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "gagal membuka: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0x%s sudah diimpor"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: kunci yang diimpor 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Sedang berjalan"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:30+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Icelandic\n"
+"Language: is\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n%10!=1 || n%100==11)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Í gangi"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Giovanni Grieco <giovanni.grc96@gmail.com>, 2017. #zanata
+# Luigi Toscano <luigi.toscano@tiscali.it>, 2017. #zanata
+# Giovanni Grieco <giovanni.grc96@gmail.com>, 2018. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Alessio <alciregi@posteo.net>, 2021, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-03-31 06:20+0000\n"
+"Last-Translator: Alessio <alciregi@posteo.net>\n"
+"Language-Team: Italian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/it/>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nessun valore specificato"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "il valore dei secondi '%s' non deve essere negativo"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "non potevo convertire '%s'a byte"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unità sconosciuta '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "valore chiave/certificato non valido"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "value 1 non è un valore consentito"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "un valore negativo non è consentito"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "percentuale '%s' fuori scala"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configurazione: OptionBinding with id \"%s\" non esiste"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configurazione: OptionBinding with id \"%s\" esiste già"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valore booleano non valido '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' non è un valore ammesso"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "il valore fornito [%d] deve essere inferiore al valore ammesso [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "il valore fornito [%d] deve essere superiore al valore ammesso [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "il percorso fornito '%s' non è assoluto."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "il percorso fornito '%s' non esiste."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "non potevo convertire '%s'a secondi"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue (): valore non impostato"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+"Non è possibile abilitare contemporaneamente più stream per il modulo '%s'"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Non è possibile abilitare lo stream '%2$s' per il modulo '%1$s': lo stato "
+"del modulo è già stato modificato"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Problema di dipendenze modulari con i Default: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Problema di dipendenze modulari con gli ultimi moduli: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Problema di dipendenze modulari: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, fuzzy, c-format
+#| msgid "failed to remove %s"
+msgid "Unable to resolve argument '%s'"
+msgstr "non è riuscito a rimuovere %s"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problema %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problema: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Nessun metadato modulare disponibile per il pacchetto modulare '%s'; non si "
+"può installare sul sistema"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "la firma non verifica per %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "impossibile da aprire (errore generico): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "impossibile verificare la chiave per %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "chiave pubblica non disponibile per %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "firma non trovata per %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "impossibile aggiungere l'elemento di installazione: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Errore durante l'esecuzione della transazione: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Errore durante l'esecuzione della transazione e non sono stati segnalati "
+"problemi!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Errore irreversibile, eseguire il ripristino del database"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "non è riuscito a trovare il pacchetto %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "impossibile aggiungere un elemento di cancellazione %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() has failed."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "non è riuscito ad aprire: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "non è possibile creare un file temporaneo: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "errore durante l'apertura del file tmp: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, fuzzy, c-format
+#| msgid "failed opening tmp file: %s"
+msgid "Failed closing tmp file %s: %s"
+msgstr "errore durante l'apertura del file tmp: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "non è possibile creare un file temporaneo %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "file repo md null"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "non posso leggere il file %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "non è riuscito a rilevare automaticamente l'architettura"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "non è riuscito a creare cache %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "errore durante il caricamento di RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "percentuale non 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "impossibile impostare i passaggi numerici: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "annullato dall'azione dell'utente"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "fatto su uno stato %1$p che non aveva un set di dimensioni! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "già al 100 %% stato [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Fonti non impostate quando si cerca di garantire il pacchetto %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Non è stato possibile garantire %1$s come repo %2$s non trovato(%3$i "
+"repository caricati)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Impossibile verificare la mancanza di fiducia: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "File scaricato per %s non trovato"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"pacchetto %1$s non può essere verificato e repo %2$s è abilitato per GPG: "
+"%3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Impossibile ottenere valore per CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Impossibile ottenere dimensioni del file system libere per %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Impossibile ottenere dimensioni del file system libere per %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"Spazio libero insufficiente in %1$s: necessario %2$s, a disposizione %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "impossibile impostare la radice"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Errore %i eseguire il test delle transazioni"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Errore %i transazione in corso"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"La transazione non è andata in fase di scrittura, ma non ha restituito alcun"
+" errore (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "impossibile aprire la directory %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "non è riuscito a rimuovere %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Impossibile creare la directory temporanea del repository \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+"Per il repository %s non è impostato né il campo mirror né il campo baseurl."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"La velocità massima è minore di quella minima. Si prega di cambiare la "
+"configurazione del minrate o throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Impossibile trovare un baseurl valido per il repository: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "pronti contro termine %s: 0x%s già importato"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, fuzzy, c-format
+#| msgid "Cannot create directory \"%s\": %s"
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Impossibile creare la directory \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "pronti contro termine %s: chiave importata 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "riattivazione: repository '%s' saltato, nessun metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "riattivazione: repository '%s' saltato, nessun hash utilizzabile."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "riattivazione: non riuscita per '%s', checksum %s non corrispondente."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"riattivazione: '%s' può essere riattivato - il checksum del metalink "
+"corrisponde."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+"riattivazione: '%s' può essere riattivato, il file repomd corrisponde."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "riattivazione: non riuscita per '%s', il file repomd non corrisponde."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Impossibile creare la directory \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Impossibile rinominare la directory \"%s\" a \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repository: uso della cache per %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Modalità solo cache abilitata, ma cache non presente per '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: download da remoto: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): Computation of SHA256 failed"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"resume non può essere utilizzato contemporaneamente con il parametro "
+"byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Inizializzazione PackageTarget non riuscita: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Non si può aprire %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Gestore del registro con ID %ld non esiste"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "In corso"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Non in corso"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Nessuna transazione in corso"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+"Tentativo di inserire l'oggetto della transazione nella transazione "
+"completata"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+"Tentativo di aggiornare l'elemento della transazione nella transazione "
+"completata"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Database Corrotto: nella tabella 'config' manca la riga 'version'"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: impossibile aprire la cron persist di storia"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Impossibile trovare un database di cronologia"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "La transazione è già iniziata!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Lo stato TransactionItem non è impostato: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
+"Impossibile aggiungere l'output della console alla transazione non salvata"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "non posso elencare le chiavi: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "non è riuscito ad aggiungere solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main () non è riuscito a scrivere i dati: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main () non è riuscito a ricaricare il file solv scritto"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) has failed: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() has failed."
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "non riuscito a calcolare il checksum RPMDB"
--- /dev/null
+# Casey Jones <nahareport@live.com>, 2018. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata, 2021.
+# Casey Jones <nahareport@yahoo.com>, 2020.
+# Sundeep Anand <suanand@redhat.com>, 2021, 2022.
+# Transtats <suanand@redhat.com>, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-03-07 14:20+0000\n"
+"Last-Translator: Transtats <suanand@redhat.com>\n"
+"Language-Team: Japanese <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/ja/>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "値が指定されていません"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "2 個目の値 '%s' は負の数にしないでください"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "'%s' を バイトへ変換できませんでした"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "不明な単位 '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "無効な値"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "値 1 は許可されません"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "負の値は許可されていません"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "パーセンテージ '%s' が範囲外にあります"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "設定: id \"%s\" を伴う OptionBinding は存在しません"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "設定: id \"%s\" を伴う OptionBinding はすでに存在します"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "無効な boolean 値 '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' 値は許可されていない値です"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "指定された値 [%d] は許可された値 [%d]より小さくしてください。"
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "指定された値 [%d] は許可された値 [%d]より大きくしてください。"
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "指定されたパス '%s' は絶対パスではありません。"
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "指定されたパス '%s' が存在しません。"
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "'%s' を 秒に変換できません"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): 値は設定されていません"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "モジュール '%s' から、さらにストリームを同時に有効にできません"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr "モジュール '%1$s' ストリーム '%2$s' を有効にできません。モジュールの状態はすでに変更されています"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "デフォルトのモジュラー依存問題: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "最新のモジュールでモジュールの依存関係の問題: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "モジュラーの依存に関する問題: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "引数 '%s' を解決できません"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr "モジュール名のみが必要です。引数の不必要な情報は無視します: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "モジュール '%s' をリセットできません。モジュールの状態はすでに変更されています"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "モジュール '%s' を無効にできません。モジュールの状態はすでに変更されています"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "モジュールデータは利用できません"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "引数の不要な情報は無視します: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr "モジュール '%1$s' ストリーム '%2$s' の依存関係ツリーの有効化中に問題: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "モジュール有効化リクエストに発生する問題:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "モジュール仕様 '%s' について、アクティブなモジュールパッケージが見つかりません"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "フェイルセーフリポジトリーからモジュール '%s' をインストールできません"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "'%s' にマッチするプロファイルが見つかりません"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "モジュール仕様 %s について、パッケージ '%s' にマッチする項目はありません"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "モジュール '%1$s' ストリーム '%2$s' のインストール中に問題: %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "モジュールインストールリクエストに発生する問題:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "モジュールリセットリクエストに発生する問題:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "モジュール無効化リクエストに発生する問題:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr "オペレーションは、モジュール '%s' ストリーム '%s' を ストリーム '%s' へと切り替える結果となります"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"有効化されたモジュールのストリームの切り替えはできません。\n"
+"モジュールからすべてのインストールされたコンテンツを削除し、'microdnf module reset <module_name>' コマンドを使用してモジュールをリセットすることを推奨します。モジュールのリセット後に、別のストリームをインストールできます。"
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "トランザクションを depsolve できませんでした; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i 問題を検出:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " 問題 %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " 問題: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr "モジュラーパッケージ '%s' のモジュラーメタデータは利用不可です; システムにインストールはできません"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "署名は %s を確認しません"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "開くことに失敗しました(ジェネリックエラー): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "%s のキーの確認に失敗しました"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "%s は公開鍵を利用できません"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "%s の署名は見つかりませんでした"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "インストールの要素の追加に失敗しました: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "トランザクションの実行中にエラーが発生しました: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "トランザクションの実行中にエラーが発生しましたが、問題は報告されませんでした!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "致命的なエラー、データベースリカバリーを実行します"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "パッケージ %s を見つけることができませんでした"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "erase 要素 %1$s(%2$i) を追加することができません"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() は失敗しました。"
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "拡張キャッシュの %s (%d) の読み込みに失敗しました: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "%2$s の %1$s 文字列はありません"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "開くことに失敗しました: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "一時ファイルを作成できません: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "tmp ファイルを開くことに失敗しました: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr "プライマリーキャッシュの %s repowriter 書き込み中に %i エラーが発生しました。エラー: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "tmp ファイル %s の終了に失敗しました: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "新たに書き込まれたプライマリーキャッシュを使用できません: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "新たに書き込まれたプライマリーキャッシュを使用できません: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "一時ファイル %s を作成できません"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr "拡張キャッシュ %s (%d) の書き込み中: repowriter の書き込みに失敗: %i、エラー: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr "拡張キャッシュの書き込み中 (%d): 一時ファイルを終了できません: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "新たに書き込まれた拡張キャッシュを使用できませんでした: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "新たに書き込まれた拡張キャッシュを使用できませんでした: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo md ファイル"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "ファイル %1$s を読み込みできません: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "リポジトリーのロード中に %s が使用できませんでした: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "MD_TYPE_PRIMARY のロードに失敗しました。"
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "リポジトリーのプライマリーデータを開くと失敗します: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "repomd の読み込みに失敗しました: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "プライマリーの読み込みに失敗しました: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "アーキテクチャーの自動検出に失敗しました"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "cachedir %s の作成に失敗しました"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "RPMDB のロードに失敗しました"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "モジュールのデフォルトは見つかりませんでした: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "パーセンテージは 100 ではありません: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "数のステップの設定に失敗しました: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "ユーザーの動作で取り消されました"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "サイズ設定のない状態 %1$p で実行されました! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "すでに 100%% の状態 [%s] にあります"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "パッケージ %s を確実にしようとする場合、ソースは設定されません"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "repo %2$s が見つからないため、%1$s を確実にすることに失敗しました (%3$i repo はロード済み)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "untrusted の確認に失敗しました: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "%s にダウンロードしたファイルが見つかりませんでした"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "パッケージ %1$s は確認できず、repo %2$s は GPG が有効になっています: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "CacheDir の値の取得に失敗しました"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "%s に filesystem をフリーサイズで取得することに失敗しました: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "%s に filesystem をフリーサイズで取得することに失敗しました"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "%1$s に十分なスペースがありません: %2$s 必要で、利用可能なのは %3$s です"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "root の設定に失敗しました"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "トランザクションテストの実行中にエラー %i"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "rpm データベースを開く際にエラー %i"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "rpmdbCookie() 関数は rpm データベースのクッキーを返しませんでした。"
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "トランザクションの実行中にエラー %i"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "トランザクションは書き込みフェーズまで行きませんでしたが、エラー(%i) は返しませんでした"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "ディレクトリー %1$s を開くことができません: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "%s の削除に失敗しました"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "不適格な Selector、フィルター内に複数の一致するオブジェクトが存在"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "操作に使用される不適格な Selector、間違った比較タイプ"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "はdistupgradeレポジトリーに属していません"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "は下位アーキテクチャがあります"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "インストール済パッケージの問題 "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "競合するリクエスト"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "非サポートのリクエスト"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "何もリクエストされていません "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "パッケージ %s は存在しません"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " はシステムから提供されます"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "いくつかの依存問題"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "パッケージの最良アップデート候補をインストールできません "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "ジョブの最良アップデート候補をインストールできません"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "パッケージ %s はモジュラーフィルタリングに一致しません"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "パッケージ %s は互換性のあるアーキテクチャーがありません"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "パッケージ %s はインストール不可です"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "パッケージ %s は除外フィルタリングに一致しません"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "%s が提供されません %s に必要です"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "%s と %s どちらもインストールできません"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "パッケージ %s は %s と競合しています。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "パッケージ %s は %s を廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "インストール済パッケージ %s は %s を廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "パッケージ %s は %s を暗に廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "パッケージ %s には %s が必要ですが、どのプロバイダーからもインストールできません"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "パッケージ %s は自己提供される %s と競合しています"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "パッケージ %s と %s 両方は %s を廃止しました"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "はdistupgradeレポジトリーに属していません"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "は下位アーキテクチャがあります"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "インストール済モジュールの問題 "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "モジュール %s は存在しません"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "モジュールの最良アップデート候補をインストールできません "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "モジュール %s は無効です"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "モジュール %s は互換性のあるアーキテクチャーがありません"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "モジュール %s はインストール不可です"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "%s が提供されませんモジュール %s に必要です"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "モジュール %s と %s どちらもインストールできません"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "モジュール %s は %s と競合しています。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "モジュール %s は %s を廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "インストール済モジュール %s は %s を廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "モジュール %s は %s を暗に廃止しました。これは %s により提供されます"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "モジュール %s には %s が必要ですが、どのプロバイダーからもインストールできません"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "モジュール %s は自己提供される %s と競合しています"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "モジュール %s と %s 両方は %s を廃止しました"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "設定されたソルバーはありません"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "%s を絶対的にすることに失敗しました"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "debugdata を %1$s へ書き込むことに失敗しました: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "目標に solv がありません"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "ソリューションがなく、保護されたパッケージを削除できません"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "可能なソリューションがありません"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "問題: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "問題 %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "操作は結果的に以下の保護されたパッケージを削除します: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Libsolv の solv_toolversion の長さ: %zu ですが、最大の想定値: %zu です"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "名前を %1$s から %2$s へ変更できませんでした: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "%1$s に権限を設定できませんでした: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "ディレクトリー %1$s を作成できません : %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "パス %1$s のstatを調べられません : %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "不正なプラットフォームモジュールのフォーマット: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "利用可能パッケージに提供される複数のモジュールプラットフォーム\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "インストール済パッケージに提供される複数のモジュールプラットフォーム\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "%s のプラットフォームモジュールの検出に失敗しました: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "%s に PLATFORM_ID が見つかりません"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "有効な Platform ID が検出されませんでした"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "モジュール '%s' の複数ストリームを有効化できません"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "repo '%s' のデフォルトが競合: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "モジュールプロファイルのインストール中:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "モジュールプロファイルの無効化中:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "モジュールストリームの有効化中:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "モジュールストリームの切り替え中:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "モジュールの無効化:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "モジュールの再設定中:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "'%s' のモジュラーフェイルセーフデータをロードできません"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "モジュール '%s:%s' のモジュラーフェイルセーフデータをロードできません"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "ディレクトリー \"%s\" を作成できません。対象モジュラーフェイルセーフデータ: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "'%s' のモジュラーフェイルセーフデータを保存できません"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "'%s' のモジュラーフェイルセーフデータを削除できません"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr "ターゲットモジュール '%s' が無効であるため、モジュラーの廃止を '%s:%s' に適用できません"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "文字列からのアップデートに失敗しました: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "名前解決に失敗しました: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "モジュラーデフォルトの解決中にエラーが発生しました: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "デフォルトのアップグレードに失敗しました: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "ストリームのアップグレードに失敗しました: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr "%s に一致するストリームがないため、モジュールの廃止を取得できません: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "共有ライブラリ \"%s\" をロードできません : %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "シンボル \"%s\" のアドレスを収集できません : %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "プラグインファイル =\"%s\" をロード中"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "プラグイン名 =\"%s\", バージョン =\"%s\" をロードしました"
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath は空白にできません"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "プラグインディレクトリー \"%s\" を読み込めません : %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "プラグイン \"%s\" をロードできません : %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "repo 一時ディレクトリー \"%s\" を作成できません: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"reldeps で '==' "
+"演算子を使用すると、未定義の動作が発生する可能性があります。これは非推奨で、将来のバージョンではサポートされなくなります。代わりに '=' "
+"演算子を使用してください。"
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "リポジトリー %s にはミラーまたは baseurl セットがありません。"
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "リポジトリー '%s' にはサポートされていないタイプがあります: 'type=%s'、スキッピング。"
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "repo '%s': 'basecachedir' が設定されていません"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr "ダウンロードの最高速度は、最低速度よりも低いです。minrate またはスロットルの設定を変更してください"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "repo '%s': 'proxy_username' は設定済みですが、'proxy_password' は設定されていません"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' は設定済みですが、'proxy_password' は設定されていません"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "repo に対して有効な baseurl を見つけられません: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "repo '%s' のGPG鍵の回収に失敗しました : %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0x%s はインポート済みです"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "ディレクトリー \"%s\" の作成に失敗しました: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: インポート済みのキー 0x%s。"
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "復元中: repo '%s' はスキップされました、metalink はありません。"
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "復元中: repo '%s' はスキップされました、使用可能なハッシュはありません。"
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "復元中: '%s' は失敗しました、%s の合計は一致しません。"
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr "復元中: '%s' は復元できます - metalink チェックサムが一致します。"
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "復元中: '%s' は復元できます - repomd が一致します。"
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "復元中: '%s' に失敗しました、repomd が一致しません。"
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "repo 送信先ディレクトリ \"%s\" を作成できません : %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "ディレクトリー \"%s\" を作成できません: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "ディレクトリー名を \"%s\" から \"%s\" へと変更できません: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: キャッシュを使用: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "キャッシュオンリーが有効になっていますが、'%s' に対するキャッシュはありません"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: リモートからダウンロード中: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "repo '%s' のメタデータのダウンロードに失敗しました : %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): SHA256 のコンピュテーションに失敗しました"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "persistdir \"%s\" を作成できません : %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume は byterangestart param と同時に使用できません"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget の初期化に失敗しました: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "%s を開くことができません: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "id %ld を伴うログハンドラーは存在しません"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "進行中"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "進行中ではありません"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "進行中のトランザクションはありません"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "完了したトランザクションにトランザクションアイテムの挿入を試みます"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "完了したトランザクションにトランザクションアイテムの更新を試みます"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "データベースが破損しています。テーブル 'config' の行 'version' がありません"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "トランスフォーマー: 履歴の残った dir を開くことができません"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "履歴のデータベースを見つけることができませんでした"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "トランザクションが開始しました!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem の状態は設定されていません: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "未保存のトランザクションにコンソールの出力を追加できません"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "キーを一覧表示できません: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "solv の追加に失敗しました"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() はデータの書き込みに失敗しました: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() は、書き込みされた solv ファイルの再ロードに失敗しました"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) は失敗しました: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() は失敗しました。"
+
+#, fuzzy
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "デフォルトのアップグレードに失敗しました: %s"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "repo に対する不正な id: %s, byte = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "RPMDB チェックサムの計算に失敗しました"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-09-01 20:21+0000\n"
+"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
+"Language-Team: Georgian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/ka/>\n"
+"Language: ka\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.18.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "მნიშვნელობა მითითებული არაა"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "დროის მნიშვნელობა წამებში '%s' უარყოფითი არ შეიძლება იყოს"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "'%s'-ის ბაიტებად გარდაქმნის შეცდომა"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "უცნობი ერთეული '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "არასწორი მნიშვნელობა"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "მნიშვნელობა 1 დაუშვებელია"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "უარყოფითი მნიშვნელობა დაუშვებელია"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "პროცენტულობა '%s' დიაპაზონს გარეთაა"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "მორგება: OptionBinding-ი id-ით \"%s\" არ არსებობს"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "მორგება: OptionBindin-ი id-ით \"%s\" უკვე არსებობს"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "არასწორი ლოგიკური მნიშვნელობა '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "მნიშვნელობა %s დაუშვებელია"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+"მინიჭებული მნიშვნელობა [%d] დასაშვებ მნიშვნელობაზე [%d] ნაკლები უნდა იყოს."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+"მინიჭებული მნიშვნელობა [%d] დასაშვებ მნიშვნელობაზე [%d] მეტი უნდა იყოს."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "მითითებული ბილიკი '%s' აბსოლუტური არაა."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "მითითებული ბილიკი '%s' არ არსებობს."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "'%s'-ის წამებში გადაყვანა შეუძლებელია"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): მნიშვნელობა მითითებული არაა"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "მოდულიდან '%s' იგივე დროს მეტ ნაკადს ვერ ჩართავთ"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"ნაკადისთვის '%2$s' მოდულის '%1$s' ჩართვა შეუძლებელია: მოდულის მდგომარეობა "
+"უკვე შეიცვალა"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "მოდულური დამოკიდებულების პრობლემა ნაგულისხმევ მნიშვნელობებთან: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "მოდულური დამოკიდებულების პრობლემა უახლეს მოდულებთან: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "მოდულური დამოკიდებულების პრობლემა: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "არგუმენტის '%s' ამოხსნა შეუძლებელია"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"საჭიროა, მხოლოდ, მოდულის სახელი. დანარჩენი ინფორმაცია გამოტოვებული იქნება "
+"არგუმენტში: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"მოდულის '%s' საწყის მნიშვნელობებზე დაბრუნება შეუძლებელია: მოდულის "
+"მდგომარეობა უკვე შეიცვალა"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "მოდულის '%s' გათიშვა შეუძლებელია: მოდულის მდგომარეობა უკვე შეიცვალა"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "მოდულური მონაცემები ხელმისაწვდომი არაა"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "გამოტოვებული იქნება არასაჭირო ინფორმაცია არგუმენტში '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"პრობლემა დამოკიდებულების ხის ჩართვისას მოდულისთვის '%1$s' ნაკადი '%2$s': "
+"%3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "მოდულის ჩართვის მოთხოვნისას აღმოჩენილი პრობლემები:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "აქტიური მოდულის პაკეტი აღმოჩენილი არაა მოდულის სპეციფიკაციისთვის '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "შეცდომებისგან დაცული რეპოზიტორიიდან მოდული '%s' ვერ დავაყენე"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "პროფილი, რომელიც '%s'-ს ემთხვევა, ვერ ვიპოვე"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+"პაკეტისთვის '%s' მოდულის სპეციფიციკაციისთვის %s დამთხვევა აღმოჩენილი არაა"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "პრობლემა დაყენებისას მოდულისთვის '%1$s' ნაკადი '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "პრობლემები, რომლებიც მოდულის დაყენების მოთხოვნისას აღმოჩნდა:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "პრობლემები, რომლებიც მოდულის განულების მოთხოვნისას აღმოჩნდა:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "პრობლემები, რომლებიც მოდულის გათიშვის მოთხოვნისას აღმოჩნდა:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"ოპერაცია მოდულის '%s' ნაკადიდან '%s' ნაკადზე '%s' გადართვას გამოიწვევდა"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"მოდულის ჩართული ნაკადების გადართვა შეუძლებელია.\n"
+"რეკომენდებულია, წაშალოთ მოდულის ყველა დაყენებული შემცველობა, გაანულოთ ის ბრძანებით 'microdnf module reset <მოდულის_სახელი>'. როცა მოდულს გაანულებთ, შეგიძლიათ სხვა ნაკადი დააყენოთ."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "ტრანზაქციის დამოკიდებულებების გადაწყვეტის შეცდომა; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "აღმოჩენილია %i პრობლემა:\n"
+msgstr[1] "აღმოჩენილია %i პრობლემა:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " პრობლემა %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " პრობლემა: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"მოდულარული პაკეტი '%s'-თვის მოდულარული მეტამონაცემები მიუწვდომელია; ვერ "
+"დაყენდება თქვენს სისტემაზე"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "%s-ის ხელმოსაწერა არ შემოწმებულა"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "%s-ის გახსნის შეცდომა (ზოგადი შეცდომა)"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "%s-ის გასაღების შემოწმების შეცდომა"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "%s-ის საჯარო გასაღები მიუწვდომელია"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "%s-ის ხელმოსაწერა ვერ ვიპოვე"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "%1$s[%2$i]-ის დაყენებს შეცდომა"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "ტრანზაქციის გაშვების შეცდომა: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "ტრანზაქციის გაშვება შეუძლებელია და ამავე დროს პრობლემები არაა!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "ფატალური შეცდომა. გაუშვით ბაზის აღდგენა"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "%s-ის პოვნის შეცდომა"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "%1$s(%2$i)-ის წაშლის შეცდომა"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv()-ის შეცდომა."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "გაფართოების კეშის %s (%d) ჩატვირთვა ჩავარდა: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "%1$s სტრიქონი %2$s-თვის არ არსებობს"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "გახსნის შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "დროებით ფაილის შექმნის შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "დროებითი ფაილის გახსნის შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"ძირითადი კეშის %s ჩაწერისას, repowriter-ის ჩაწერის შეცდომა: %i, შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "დროებითი ფაილის დახურვის შეცდომა (%s): %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "შეცდომა ახლად ჩაწერილი ძირითადი კეშის გამოყენებისას: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "ახლად ჩაწერილი ძირითადი კეშის გამოყენების შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "დროებითი ფაილის შექმნის შედცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"გაფართოების კეშის %s (%d) ჩაწერისას: repowriter-ის ჩაწერა ჩავარდა: %i, "
+"შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"გაფართოების კეშის (%d) ჩაწერისას: დროებითი ფაილის დახურვა შეუძლებელია: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "ახლად ჩაწერილი გაფართოების კეშის გამოყენება ჩავარდა: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "ახლად ჩაწერილი გაფართოების კეშის გამოყენება ჩავარდა: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "რეპოზიტორიის ცარიელი md ფაილი"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "%1$s-ის წაკითხვის შეცდომა: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "რეპოზიტორიის ჩატვირთვისას %s-ის გამოყენება ჩავარდა: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "MD_TYPE_PRIMARY-ის ჩატვირთვს შეცდომა."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "რეპოზიტორიის ძირითადი მონაცემების გახსნის შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "RepoMD-ის ჩატვირთვის შეცდომა: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "პირველადი ჩატვირთვა ჩავარდა: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "არქიტექტურის გამოცნობის შეცდომა"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "ქეშის საქაღალდის (%s) შექმნის შეცდომა"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "RPMDB-ის ჩატვირთვის შეცდომა"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "მოდულის ნაგულისხმები მნიშვნელობები ნაპოვნი არაა: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "პროცენტები 100 არაა: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "ნაბიჯების რიცხვის დაყენების პრობლემა: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "გაუქმებულია მომხმარებლის ქმედების გამო"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "დამთავრდა მდომარეობაში %1$p, სდაც მას ზომა ჯერ არ გააჩნდა! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "უკვე 100%%-ითაა შევსებული [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "პაკეტში %s დასარწმუნებლად წყარო ნაპოვნი არაა"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "%1$s-ში როგორც რეპო %2$s ნაპოვნი არაა (ჩატვირთულია %3$i რეპო)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "არასანდოს შემოწმების პრობლემა: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "%s-ის გადმოსაწერი ფაილის მოძებნის პრობლემა"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"პაკეტი %1$s არ შეიძლება შემოწმდეს და რეპო %2$s-ს GPG აქვს ჩართული: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "CacheDir-ის მნიშვნელობის მიღების პრობლემა"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "ფაილური სისტემის (%s) ზომის მიღების პრობლემა: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "ფაილური სისტემის (%s) თავისუფალი ადგილის მიღების პრობლემა"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"%1$s-ზე საკმარისი თავისუფალი ადგილი არაა: საჭიროა: %2$s, ხელმისაწვდომია %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "root-ის დაყენების პრობლემა"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "ტრანზაქციის ტესტის შეცდომა: %i"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "შეცდომა %i rpm-ის ბაზის გახსნისას"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "ფუნქციამ rpmdbCookie() rpm-ის ბაზის ქუქი არ დააბრუნა."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "ტრანზაქციის გაშვების შეცდომა: %i"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"ტრანზაქცია არ გადასულა ჩაწერის ფაზაზე, მაგრამ შეცდომა არ დაუბრუნებია (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "საქაღალდის გახსნის შეცდომა (%1$s:%2$s)"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "%s-ის გაშვების შეცდომა"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "არასწორად ჩამოყალიბებული ამრჩევი, ფილტრში მრავალი დამთხვევის ობიექტით"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"ამ ოპერაციისთვის გამოყენებული არასწორი სელექტორი: შედარების არასწორი ტიპი"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s %s-დან distupgrade რეპოზიტორიას არ მიეკუთვნება"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s %s-დან უფრო დაბალი არქიტექტურა აქვს"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "პრობლემა დაყენებულ პაკეტთან "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "ურთიერთგამომრიცხავი მოთხოვნები"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "მხარდაუჭერელი მოთხოვნა"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "მოთხოვნილ სახელს პაკეტი არ შეესაბამება "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "პაკეტი %s არ არსებობს"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " მოწოდებულია სისტემის მიერ"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "დამოკიდებულების რამდენიმე პრობლემა"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "პაკეტისთვის განახლების საუკეთესო კანდიდატის დაყენების შეცდომა "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "ამოცანის პირობებისთვის საუკეთესო კანდიდატის დაყენების შეცდომა"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "%s %s-დან პაკეტი გაფილტრულია მოდულური ფილტრის საშუალებით"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "%s პაკეტს %s-დან თავსებადი არქიტექტურა არ გააჩნია"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "პაკეტი %s %s-დან დაყენებადი არაა"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "%s %s-დან პაკეტი გაფილტრულია ამოღების ფილტრის მიერ"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "%s-ს, რომელიც სჭირდება %s-ს %s-დან, არაფერი ემთხვევა"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "%s-ს %s-დან და %s-ს %s-დან ერთდროულად ვერ დააყენებთ"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "პაკეტი %s %s-დან კონფლიქტშია %s-სთან, რომელსაც %s გვაწოდებს, %s-დან"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+"პაკეტი %s %s-დან მოძველებულად აცხადებს %s-ს, რომელსაც გვაწოდებს %s %s-დან"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+"დაყენებული პაკეტი %s მოძველებულად აცხადებს %s, რომელსაც გვაწოდებს %s %s-დან"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"პაკეტი %s %s-დან პირდაპირ ნიშნავს %s-ს, რომელიც წარმოდგენილია %s-ის სახით "
+"%s-დან, მოძველებულად"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"პაკეტს %s-ს %s-დან სჭირდება %s, მაგრამ ვერ ვაყენებ ვერცერთ პაკეტს, რომელიც "
+"მას წარმოადგენს"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+"პაკეტს %s-ს %s-დან გააჩნია კონფლიქტი %s-სთან, რომელსაც თვითონვე წარმოადგენს"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "ორივე პაკეტი %s %s-დან და %s %s-დან, მოძველებულად ნიშნავს %s-ს"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s %s-დან distupgrade რეპოზიტორიას არ მიეკუთვნება"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s-ს %s-დან უფრო დაბალი არქიტექტურა გააჩნია"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "პრობლემა დაყენებულ მოდულთან "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "მოდული %s არ არსებობს"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "მოდულის განახლების საუკეთესო კანდიდატის დაყენების შეცდომა "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "მოდული %s %s-დან გამორთულია"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "მოდულს %s %s-დან თავსებადი არქტიტექტურა არ გააჩნია"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "მოდული %s %s-დან დაყენებადი არაა"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "არაფერი წარმოადგენს %s-ს, რომელიც საჭიროა მოდულისთვის %s %s-დან"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "ორივე მოდულის, %s %s-დან და %s %s-დან ერთდროულად დაყენება შეუძლებელია"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+"მოდულს %s %s-დან აქვს კონფლიქტი %s-თან, რომელიც წარმოდგენილია %s-ის მიერ "
+"%s-დან"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+"მოდული %s %s-დან მონიშნულია მოძველებულად %s-ის მიერ, რომელიც წარმოდგენილია "
+"%s-ით %s-დან"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+"დაყენებული მოდული %s მოძველებულად ნიშნავს %s-ს, რომელიც წარმოდგენილია %s-ის "
+"სახით %s-დან"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"მოდული %s %s-დან პირდაპირ ნიშნავს მოძველებულად %s-ს, რომელიც წარმოდგენილია "
+"%s-ის სახით %s-დან"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"მოდულს %s %s-დან სჭირდება %s, მაგრამ შესაბამისი ყველა პაკეტის დაყენება "
+"შეუძლებელია"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+"მოდულს %s %s-დან გააჩნია კონფლიქტი %s-თან, რომელსაც თვითონვე წარმოადგენს"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "ორივე მოდული %s %s-დან და %s %s-დან %s-ს მოძველებულად ნიშნავენ"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "გადამწყვეტი მითითებული არაა"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "%s-ის აბსოლუტურად გადაქცევა შეუძლებელია"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "გასამართი ინფორმაციის %1$s-ში ჩაწერის შეცდომა: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "სამიზნეში solv-ი არაა"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "გადაწყვეტის გარეშე. დაცული პაკეტის წაშლა შეუძლებელია"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "გადაწყვეტა შეუძლებელია"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "პრობლემა: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "პრობლემა %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "ოპერაციას დასჭირდება შემდეგი დაცული პაკეტების წაშლა: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+"Libsolv-ის solv_toolversion: %zu სიგრძის, მაგრამ ჩვენ მაქსიმუმ: %zu-ს "
+"ველოდით"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "%1$s-ის %2$s-ზე გადარქმევის შეცდომა: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "%1$s-ზე წვდომების დაყენების შეცდომა: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "საქაღალდის (%1$s) შექმნის შეცდომა: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "ბილიკის (%1$s) პოვნის შეცდომა: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "პლატფორმის მოდულის არასწორი მოდული: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "ხელმისაწვდომი პაკეტები მრავალი მოდულის პლატფორმას წარმოადგენენ\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "დაყენებული პაკეტები მრავალი მოდულის პლატფორმას წარმოადგენენ\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "პლატფორმის მოდულის პოვნა (%s) წარუმატებელია: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "%s-ში PLATFORM_ID ნაპოვნი არაა"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "პლატფორმის ID არასწორია"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "მოდულისთვის (%s) მრავალი ნაკადის ჩართვა შეუძლებელია"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "რეპოზიტორიას (%s) გააჩნია კონფლიქტური ნაგულისხმები მნიშვნელობები: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "მოდულის პროფილების დაყენება\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "მოდულის პროფილების გათიშვა\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "მოდულური ნაკადების ჩართვა\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "მოდულური ნაკადების გადართვა\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "გაითიშება მოდულები\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "მოდულების საწყის მნიშვნელობებზე დაბრუნება\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "მოდულის უსაფრთხო მონაცემების ჩატვირთვის შეცდომა: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "მოდულარული უსაფრთხო მონაცემების ჩატვირთვის შეცდომა მოდულისთვის %s: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+"საქაღალდის (%s) შექმნის შეცდომა მოდულარული უსაფრთხო მონაცემებისთვის: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "მოდულარული უსაფრთხო მონაცემების %s-ში შენახვის პრობლემა"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "მოდულარული უსაფრთხო მონაცემების წაშლის შეცდომა %s-დან"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"მოდულური მოძველებულობის '%s:%s'-ზე გადატარება შეუძლებელია, რადგან სამიზნე "
+"მოდული '%s' გათიშულია"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "სტრიქონიდან განახლების შეცდომა: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "გადაწყვეტის პრობლემა: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "შეცდომა მოდულური ნაგულისხმევების ამოხსნისას: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "ნაგულისხმების განახლების შეცდომა: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "ნაკადების განახლების შეცდომა: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"მოდულის მოძველებულების მიღება შეუძლებელია, რადგან %s-ს ნაკადი არ ემთხვევა: "
+"%s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "ზიარი ბიბლიოთეკის (%s) ჩატვირთვის შეცდომა: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "სიმბოლოსთვს (%s) მისამართის პოვნის შეცდომა: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "დამატების ფაილის ჩატვირთვა \"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "ჩატვირთულია გაფართოება. სახელი=\"%s\", ვერსია=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() საქაღალდის ბილიკი ცარიელი ვერ იქნება"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "დამატებების საქაღალდის(%s) წაკითხვის შეცდომა: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "დამატების (%s) ჩატვირთვის შეცდომა: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "დროებითი დირექტორიის (%s) შექმნის შეცდომა: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"ოპერატორის '==' დამოკიდებულებებში გამოყენებამ შეიძლება გამოუცნობი ქცევა "
+"გამოიწვიოს. ის მოძველებულია და მისი მხარდაჭერა მომავალ ვერსიებში საბოლოოდ "
+"გაქრება. სამაგიეროდ, '=' ოპერატორი გამოიყენეთ."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "რეპოზიტორიას (%s) არც სარკე აქვს მითითებული, არც baseurl."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "რეპოზიტორიის (%s) მხარდაუჭერელი ტიპი: 'type%s'. გამოტოვება."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "რეპოზიტორია '%s': 'basecachedir' დაყენებული არაა"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"გადმოწერის მაქსიმალური სიჩქარე მინიმუმზე ნაკლება. გთხოვთ შეცვალოთ "
+"კონფიგურაცია"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"რეპოზიტორია '%s': 'proxy_username' დაყენებულია, 'proxy_password' კი - არა"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' დაყენებულია, 'proxy_password' კი - არა"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "რეპოსთვის (%s) baseurl-ი ხელმიუწვდომელია"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "რეპოსთვის (%s) GPG გასაღებების მიღების პრობლემა: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "რეპო %s: 0x%s უკვე შემოტანილია"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "შეცდომა საქაღალდის (\"%s\") შექმნისას: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "რეპო %s: შემოტანილია გასაღები 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "აღდგენა: რეპო %s გამოტოვებულია, მეტაბმული არ გააჩნია."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "აღდგენა: რეპო %s გამოტოვებულია გამოყენებადი ჰეშის არარსებობის გამო."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "აღდგენა: %s-ის შეცდომა, %s-ის ჯამი არ ემთხვევა."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"აღდგენა: %s-ის აღდგენა შესაძლებელია, მეტაბმულის საკონტროლო ჯამები ერთმანეთს "
+"ემთხვევა."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "აღდგენა: %s-ის აღდგენა შეუსაძლებელია - repomd ემთხვევა."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "აღდგენა: %s-ის შეცდომა. repomd არ ემთხვევა."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "რეპოს დანიშნულების საქაღალდის (%s) შექმნის შეცდომა: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "საქაღალდის(%s) შექმნის შეცდომა: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "საქაღალდის გადარქმევის შეცდომა (%s-დან %s-მდე): %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "რეპო: %s-თვის ქეშის გამოყენება"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Cache-only ჩართულია, მაგრამ %s-ის ქეში არ არსებობს"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "რეპო: %s-დან გადმოწერა"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "რეპოს (%s) მეტამონაცემების გადმოწერის შეცდომა: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): SHA256-ის გამოთვლის შეცდომა"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "მუდმივი საქაღალდის (%s) შექმნა შეუძლებელია: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "byterangestart პარამეტრით გაგრძელება შეუძლებელია"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget-ის ინიციალიზაციის შეცდომა: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "%s-ის გახსნის შეცდომა: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "ჟურნალის მომვლელი id-ით %ld არ არსებობს"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "მიმდინარეობა"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "ar არ მიმდინარეობს"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "ამჟამად ტრანზაქცია გაშვებული არაა"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "ტრანზაქციის უკვე დასრულებულ ტრანსაქციაში ჩასმის მცდელობა"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "დასრულებულ ტრანზაქციაში ელემენტის განახლების მცდელობა"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "ბაზა დაზიანებულია: ცხრილში 'config' მწკრივი 'version' არ არსებობს"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "გადამქმნელი: ისტორიის მუდმივი საქაღალდის გახსნის შეცდომა"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "სტორიის ბაზის გახსნის შეცდომა"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "ტრანზაქცია უკვე დაიწყო!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "ტრანზაქციის მდგომარეობა დაყენებული არაა: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "შეუნახავ ტრანზაქციაში კონსოლის გამოტანის დამატება შეუძლებელია"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "გასაღებების სიის ჩვენების პრობლემა: %s"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:48+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Kannada\n"
+"Language: kn\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "ಪ್ರಗತಿಯಲ್ಲಿದೆ"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# simmon <simmon@nplob.com>, 2021.
+# Kim InSoo <simmon@nplob.com>, 2022.
+# 김인수 <simmon@nplob.com>, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-04-01 09:19+0000\n"
+"Last-Translator: 김인수 <simmon@nplob.com>\n"
+"Language-Team: Korean <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/ko/>\n"
+"Language: ko\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "값이 지정되지 않았습니다"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "초 값 '%s 음수가 아니어야합니다"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "변환 할 수 없습니다 '%s'~ 바이트"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "알 수없는 단위 '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "잘못된 값"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "값 1은 허용되지 않습니다"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "음수 값은 허용되지 않습니다"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "백분율 '%s' 범위를 벗어났습니다"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "구성 : ID가 \"%s\" 존재하지 않는다"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "구성 : ID가 \"%s\" 이미 존재 함"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "유효하지 않은 부울 값 '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s'는 허용 된 값이 아닙니다"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "주어진 값 [%d] 허용 된 값보다 작아야합니다 [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "주어진 값 [%d] 허용 된 값보다 커야합니다 [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "주어진 경로 '%s절대적이지 않다."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "주어진 경로 '%s' 존재하지 않는다."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "변환 할 수 없습니다 '%s'초까지"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue () : 값이 설정되지 않았습니다"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "동시에 모듈 '%s’에서 다른 스트림을 활성화 할 수 없습니다"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr "모듈 '%1$s' 스트림 '%2$s 을 활성화 할 수 없습니다: 모듈 상태가 이미 변경되었습니다"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "기본설정에 모듈 의존성 문제: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "최신 모듈에 모듈 의존성 문제: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "모듈러 의존성 문제: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "인수 %s를 해결 할 수 없습니다"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr "모듈 이름만 필요합니다. 인수에서 불필요한 정보를 무시합니다: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "모듈 '%s 를 재설정 할 수 없습니다: 모듈 상태가 이미 변경되었습니다"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "모듈 '%s'사용 할 수 없습니다: 모듈 상태는 이미 적재되었습니다"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "모듈러 자료를 이용 할 수 없습니다"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "인수: '%s'에 불필요한 정보를 무시하기"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr "모듈 '%1$s' 스트림 '%2$s': %3$s 위해 의존성 트리의 활성화하는 중에 발생하는 문제"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "모듈 활성화 요청에 나타난 문제:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "모듈 상세 '%s'를 위한 활성 모듈 꾸러미가 없습니다"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "실패-방지 저장소에서 모듈 '%s'를 설치 할 수 없습니다"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "'%s'와 일치하는 프로파일을 찾을 수 없습니다"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "꾸러미 '%s'가(모듈 상세 %s에 대한) 일치하지 않습니다"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "모듈 '%1$s' 스트림 '%2$s': %3$s 위해 설치 중에 발생하는 문제"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "모듈 설치 요청을 위해 나타난 문제:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "모듈 초기화 요청을 위해 나타난 문제:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "모듈 비활성화 요청을 위해 나타난 문제:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr "이 동작은 모듈 '%s'' 스트림 ‘%s'에서 스트림 '%s'로의 전환 결과입니다"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"활성화된 모듈 스트림을 전환 할 수 없습니다.\n"
+"설치된 모든 내용을 모듈에서 제거하고 ‘<module_name>' 명령을 사용하여 모듈을 재설정하는 것이 좋습니다. 모듈을 재설정한 후, 다른 스트림을 설치 할 수 있습니다."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "연결을 해제 할 수 없습니다; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i 발견 된 문제 :\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " 문제 %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " 문제: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr "모듈러 꾸러미 '%s'에 사용 가능한 모듈러 메타데이터가 없으며; 시스템에 설치 할 수 없습니다"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "서명이 확인하지 않음 %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "열지 못했습니다 (일반 오류). %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "에 대한 키를 확인하지 못했습니다. %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "사용할 수없는 공개 키 %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "서명이 없습니다. %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "설치 요소를 추가하지 못했습니다. %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "연결 실행 오류 : %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "연결을 실행하는 중 오류가 발생했으며 아무런 문제도 보고되지 않았습니다!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "치명적인 오류, 데이터베이스 복구 실행"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "꾸러미를 찾지 못했습니다. %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "요소 지우기를 추가 할 수 없습니다. %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() 실패하였습니다."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "확장 캐쉬 %s (%d) 적재 중 실패함: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "%2$s에 %1$s 문자열이 없습니다"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "열지 못했습니다 : %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "임시 파일을 만들 수 없습니다. %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "여는 tmp 파일을 열지 못했습니다. %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr "기본 캐쉬 %s를 쓰는 동안에 repowriter 쓰기가 실패함: %i, 오류: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "tmp 파일을 닫는데 실패함 %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "새롭게 작성된 기본 캐쉬를 사용하는데 실패함: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "새롭게 작성된 기본 캐쉬를 사용하는데 실패함: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "임시 파일을 만들 수 없습니다. %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr "확장 캐쉬 %s (%d)를 쓰는 동안: repowriter 쓰기가 실패함: %i, 오류: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr "확장 캐쉬 (%d)를 쓰는 동안: 임시 파일을 닫을 수 없습니다: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "새롭게 작성된 확장 캐쉬를 사용하는데 실패함: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "새롭게 작성된 확장 캐쉬를 사용하는데 실패함: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo md 파일"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "파일을 읽을 수 없습니다. %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "저장소를 적재하는 동안에 %s를 사용하는데 실패함: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "MD_TYPE_PRIMARY를 적재하지 못했습니다."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "저장소 기본 자료를 여는데 실패함: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "repomd 적재하는데 실패함: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "기본 적재하는데 실패함: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "구조 자동 검색에 실패했습니다"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "캐쉬 된 생성 실패 %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "RPMDB로드 실패"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "모듈 기본 설정을 찾을 수 없습니다: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "백분율이 아닌 백분율 : %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "숫자 단계를 설정하지 못했습니다. %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "사용자 작업에 의해 취소됨"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "국가에서 행해진 %1$p 크기가 설정되지 않았습니다. [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "이미 100 %% 상태 [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "꾸러미 %s를 확인 하려고 할 때 원천이 설정되지 않았습니다"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "보장하지 못함 %1$s 레포로서 %2$s 찾을 수 없음 (%3$i repos loaded)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "신뢰할 수 없는지 확인하지 못했습니다. "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "에 대한 내려받기 파일 %s 찾을 수 없음"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "꾸러미 %1$s 확인 및 복구 할 수 없습니다. %2$s GPG 사용 설정 됨 : %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "CacheDir에 대한 값을 가져 오는 데 실패했습니다"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "에 대한 파일 시스템 크기를 가져 오는 데 실패했습니다. %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "에 대한 파일 시스템 크기를 가져 오는 데 실패했습니다. %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "여유 공간이 부족합니다. %1$s: 필요 %2$s, 이용 가능 %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "루트를 설정하지 못했습니다"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "%i 연결 실행 중 오류"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "rpm 데이타베이스를 여는 동안 오류 %i가 발생했습니다"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "rpmdbCookie() 함수는 rpm 데이타베이스의 쿠키를 반환하지 않습니다."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "오류 %i 실행중인 연결"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "연결이 쓰기 단계로 이동하지 않았지만 오류를 반환하지 않았습니다 (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "디렉토리를 열 수 없습니다. %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "제거하지 못했습니다. %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "잘못된 형식의 선택기, 필터에 일치하는 개체가 여러 개 있음"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "조작에 잘못 형성된 선택자, 잘못된 비교 유형"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s에서 %s 는 distupgrade 저장소에 속하지 않습니다"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s에서 %s 는 하위 구조를 갖고 있습니다"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "설치된 꾸러미 문제 "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "충돌하는 요청"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "지원되지 않는 요청"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "요청이 없습니다 "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "꾸러미 %s가 존재하지 않습니다"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " 시스템에서 제공"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "종속성 문제"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "꾸러미에 가장 적합한 최신화 선택을 설치 할 수 없습니다 "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "작업에 가장 적합한 선택을 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "%s에서 꾸러미 %s가 모듈식으로 걸러 제거됩니다"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "%s에서 꾸러미 %s는 호환 구조가 없습니다"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "%s에서 꾸러미 %s는 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "%sㅇ[사 꾸러미 %s가 걸러지는 것에서 제외되었습니다"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "어떤 것도 %s에서 %s에 의해 필요한 %s를 제공하지 않습니다"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "%s에서 %s 및 %s에서 %s 모두 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "꾸러미 %s에서 %s는 %s에서 %s에 의해 제공된 %s와 충돌합니다"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s에서 꾸러미 %s는 %s에서 %s의해 제공된 %s를 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "설치된 꾸러미 %s는 %s에서 %s에 의해 제공된 %s를 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "%s에서 꾸러미 %s가 %s에서 %s에 의해 제공된 %s를 암시적으로 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s에서 꾸러미 %s는 %s가 필요하지만, 공급자가 없어 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "%s에서 꾸러미 %s는 자체적으로 제공된 %s와 충돌합니다"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "%s에서 꾸러미 %s 및 %s에서 %s는 모두 %s에서 폐기되었습니다"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s에서 %s는 distupgrade 저장소에 속하지 않습니다"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s에서 %s는 하위 구조를 갖습니다"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "설치된 모듈 문제 "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "모듈 %s이 존재하지 않음"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "모듈에 가장 적합한 최신화 추천을 설치 할 수 없습니다 "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "모듈 %s에서 %s는 사용 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "모듈 %s에서 %s는 호환되는 구조를 가지고 있지 않습니다"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "%s에서 모듈 %s는 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "어떤 것도 %s에서 모듈 %s에 의해 필요한 %s를 제공하지 않습니다"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "%s에서 모듈 %s 및 %s에서 %s를 모두 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "%s에서 모듈 %s가 %s에서 %s에 의해 제공된 %s와 충돌합니다"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s에서 모듈 %s가 %s에서 %s에 의해 제공된 %s를 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "설치된 모듈 %s 가 %s에서 %s에 의해 제공된 %s를 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "%s에 의해 모듈 %s가 %s에서 %s에 의해 %s를 암시적으로 폐기합니다"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s에서 모듈 %s는 %s 가 필요하지만, 공급 업체가 없어 설치 할 수 없습니다"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "%s에서 모듈 %s가 자체적으로 제공된 %s와 충돌합니다"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "%s에서 모듈 %s 및 %s에서 %s 모두는 %s에서 폐기되었습니다"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "solver 설정 없음"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "%s 절대값을 생성을 실패하였습니다"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "%1$s: %2$s에 디버그자료 쓰기를 실패했습니다"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "목표에 solv가 없다"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "해결책 없음, 보호 된 꾸러미를 제거 할 수 없음"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "해결책 없음"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "문제: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "문제 %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "이 작업으로 인해 다음과 같은 보호 꾸러미가 제거됩니다. "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Libsolv의 solv_toolversion은 %zu 길이지만 최대값은 %zu로 예상됩니다"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "%1$s 을 %2$s: %3$s에 이름 바꾸기 실패"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "%1$s: %2$s에 perms 설정 실패하였습니다"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "디렉토리를 생성 할 수 없습니다 %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "경로 %1$s: %2$s stat 할 수 없습니다"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "잘못된 형식의 기반 모듈: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "사용 가능한 꾸러미로 제공되는 다중 모듈 기반\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "설치된 꾸러미로 제공되는 다중 모듈 기반\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "%s 실패한: %s 에서 기반(Platform) 모듈 감지"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "%s에서 PLATFORM_ID가 누락됨"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "유효한 기반(Platform) ID가 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "모듈 '%s’를 위해 다중 스트림을 활성화 할 수 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "저장소 '%s: %s'와 기본 설정이 충돌합니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "모듈 프로파일 설치:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "모듈 프로파일 비활성화:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "모듈 스트림 활성화:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "모듈 스트림 전환:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "모듈 비활성화:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "모듈 재설정:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "'%s'에서 모듈식 Fail-Safe 자료를 적재 할 수 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "모듈 '%s:%s'에 대해 모듈식 Fail-Safe 자료를 적재 할 수 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "모듈식 Fail-Safe 데이터에 대한 “%s\" 디렉토리를 만들 수 없습니다: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "모듈식 Fail Safe 자료를 '%s'에 저장 할 수 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "'%s'에서 모듈식 Fail Safe 자료를 제거 할 수 없습니다"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr "'%s:%s'에 사용되지 않는 모듈을 적용할 수 없습니다(대상 모듈 '%s'가 비활성화 되어 있기 때문에)"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "문자열에서 최신화하지 못했습니다: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "해결하지 못했습니다: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "모듈식 기본값을 해결하는 동안 오류가 발생했습니다: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "기본값을 최신화에 실패하였습니다: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "스트림 최신화에 실패하였습니다: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr "%s: %s 일치하는 스트림이 없기 때문에 구식 모듈을 검색 할 수 없습니다"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "공유 라이브러리\"%s\": %s 를 적재 할 수 없습니다"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "기호 \"%s\": %s 의 주소를 가져 올 수 없습니다"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "플러그인 파일 적재중=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "적재된 플러그인 이름=\"%s\", 버전=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath는 비워 둘 수 없습니다"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "플러그인 디렉토리 \"%s\": %s 를 읽을 수 없습니다"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "플러그인\"%s\": %s를 적재 할 수 없습니다"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "임시 저장소 디렉토리를 만들 수 없습니다 \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"reldeps에 '=='연산자를 사용하면 정의되지 않은 동작이 발생할 수 있습니다. 이 연산자는 더 이상 사용되지 않으며, 향후 "
+"버전에서는 지원이 중단됩니다. 대신 '=' 연산자를 사용하세요."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "저장소 %s 는 연결주소 또는 baseurl 구성을 갖고 있지 않습니다."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "저장소 '%s'는 지원하지 않는 유형: 'type=%s'이며, 건너뜁니다."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "repo '%s': 'basecachedir가 구성되어 있지 않습니다"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr "최대 내려받기 속도는 최저보다 낮습니다. 최저속도나 변환 환경구성을 변경해 주세요"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "repo '%s': 'proxy_username' 는 구성되어 있지만 'proxy_password'가 없습니다"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' 이 구성되어 있지만 'proxy_password'가 없습니다"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "repo: %s 를 위해 유효한 baseurl을 찾을 수 없습니다"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "repo '%s': %sf 를 위해 GPG key 가져오기에 실패하였습니다"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0x%s를 이미 가져왔습니다"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "디렉토리를 생성 할 수 없습니다 \"%s\": %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: 0x%s 키를 가져왔습니다."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "부활: repo '%s' 건너 뛰었으며, 메타링크가 없습니다."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "부활: repo '%s'건너 뛰었으며, 사용 가능한 해쉬가 없습니다."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "부활 : '%s'에 실패하고, %s 합과 일치하지 않음."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr "부활: '%s'는 부활 할 수 있습니다 - 메타링크 체크섬이 일치합니다."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "부활: '%s'는 부활 할 수 있습니다 - repomd가 일치합니다."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "부활: '%s'에 실패하고, 일치하지 않은 repomd."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "repo 목적지 디렉토리 \"%s\": %s 를 생성 할 수 없습니다"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "디렉토리를 만들 수 없습니다 \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "디렉토리 \"%s\"를 \"%s\": %s로 변경 할 수 없음"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: 캐쉬 사용: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "캐쉬만 사용 가능하지만 '%s'를 위해 캐쉬가 없습니다"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: 원격에서 내려받기 중: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "repo를 위한 메타자료 내려받기에 실패하였습니다 '%s': %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): SHA256 계산에 실패했습니다"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "persistdir \"%s\": %s 를 생성 할 수 없습니다"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "이력서는 byterangestart 매개 변수와 동시에 사용 할 수 없습니다"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget 초기화에 실패했습니다: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "열 수 없습니다 %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "ID가 있는 로그 처리기 %ld가 존재하지 않습니다"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "진행 중"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "진행 중이 아님"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "진행 중인 연결 없음"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "연결 항목을 완료된 연결에 삽입하려고 시도했습니다"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "완료된 연결에서 연결 항목 최신화를 시도합니다"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "데이타베이스가 오염되었습니다: 테이블 'config'에 'version' 행이 없습니다"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "변형: persist dir 기록을 열 수 없습니다"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "기록 데이타베이스를 찾을 수 없습니다"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "연결이 이미 시작되었습니다!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem 상태가 설정되지 않았습니다. %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "저장되지 않은 연결에 콘솔 출력을 추가 할 수 없습니다"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "열쇠를 나열 할 수 없습니다 : %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "solv를 추가하지 못했습니다"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() 실패한 쓰기 자료: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main ()이 작성된 solv 파일을 다시 적재하지 못했습니다"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) 실패하였습니다: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() 실패하였습니다."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "모듈 artifact NERVRA '%s'를 구문 분석하는데 실패하였습니다"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "RPMDB 체크섬 계산 실패"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-11 01:37+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset "
+"the module using 'microdnf module reset <module_name>' command. After you "
+"reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955 libdnf/repo/Repo.cpp:1029
+#: libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of "
+"minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 03:58+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Maithili\n"
+"Language: mai\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "प्रगतिमे"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 04:03+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Malayalam\n"
+"Language: ml\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "പുരോഗമിക്കുന്നു"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 04:08+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Marathi\n"
+"Language: mr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "कार्य चालू आहे"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 04:14+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Norwegian Bokmål\n"
+"Language: nb\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Pågår"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Geert Warrink <geert.warrink@onsnet.nu>, 2017. #zanata, 2020, 2021, 2022, 2023.
+# Richard E. van der Luit <fedoraproject@veneax.nl>, 2020.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-08-10 14:21+0000\n"
+"Last-Translator: Geert Warrink <geert.warrink@onsnet.nu>\n"
+"Language-Team: Dutch <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/nl/>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.18.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "geen waarde gespecificeerd"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "seconde waarde '%s' mag niet negatief zijn"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "kon '%s' niet converteren naar bytes"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "onbekende unit '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "ongeldige waarde"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "waarde 1 wordt niet toegestaan"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "negatieve waarde wordt niet toegestaan"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "percentage '%s' valt buiten de reeks"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configuratie: OptionBinding met id \"%s\" bestaat niet"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configuratie: OptionBinding met id \"%s\" bestaat al"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "ongeldige booleaanse waarde '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' is geen toegestane waarde"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "gegeven waarde [%d] moet kleiner zijn dan de toegestane waarde [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "gegeven waarde [%d] moet groter zijn dan de toegestane waarde [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "gegeven pad '%s' is niet absoluut."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "gegeven pad '%s' bestaat niet."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "kon '%s' niet converteren naar seconden"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Waarde niet ingesteld"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Kan niet meer streams voor module '%s' gelijktijdig aanzetten"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Kan module '%1$s' stream '%2$s' niet inschakelen: status van module is al "
+"gewijzigd"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Modulair afhankelijkheidsprobleem met Standaard: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Modulair afhankelijkheidsprobleem met de laatste modules: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Modulair afhankelijkheidsprobleem: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Kan argument '%s' niet oplossen"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Alleen de modulenaam is vereist. Onnodige informatie in argument wordt "
+"genegeerd: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "Kan module '%s' niet herstellen: status van de module is al gewijzigd"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Kan module '%s' niet uitschakelen: status van module is al gewijzigd"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Geen modulaire data beschikbaar"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Onnodige informatie in argument wordt genegeerd: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Probleem tijdens het inschakelen van de afhankelijkheidsboom voor module "
+"'%1$s' stream '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Er zijn problemen opgetreden met het verzoek om module-inschakeling:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Er zijn geen actieve modulepakketten gevonden voor module spec '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Kan module %s van fail-safe repository niet installeren"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Geen profiel gevonden overeenkomend met '%s'"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Geen overeenkomst voor pakket '%s' voor module spec %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+"Probleem tijdens het installeren voor module '%1$s' stream '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Er zijn problemen opgetreden bij het module installatie verzoek:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+"Er zijn problemen opgetreden met het verzoek om een module opnieuw in te "
+"stellen:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+"Er zijn problemen opgetreden voor het verzoek om module-uitschakeling:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"De operatie zou resulteren in het omschakelen van module '%s' stream '%s' "
+"naar stream '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Het is niet mogelijk om geactiveerde streams van een module te schakelen.\n"
+"Het wordt aanbevolen om alle geïnstalleerde inhoud van de module te verwijderen en de module te resetten met het commando 'microdnf module reset <module_name>'. Nadat je de module opnieuw hebt ingesteld, kun je de andere stream installeren."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Kan depsolve niet uitvoeren voor transactie; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i probleem gedetecteerd:\n"
+msgstr[1] "%i problemen gedetecteerd:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Probleem %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Probleem: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Geen modulaire metadata beschikbaar voor modulair pakket '%s'; kan niet "
+"worden geïnstalleerd op het systeem"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "handtekening verifieert niet voor %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "open(generic error) mislukte: %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "verifiëren van sleutel voor %s mislukte"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "publieke sleutel niet beschikbaar voor %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "geen handtekening gevonden voor %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "kan installatie-element niet toevoegen: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Fout bij het uitvoeren van transactie: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Fout bij het uitvoeren van transactie, maar er werden geen problemen "
+"gerapporteerd!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Fatale fout, databaseherstel uitvoeren"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "vinden van pakket %s mislukte"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "kon geen wis-element toevoegen %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() is mislukt."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Laden van extensiecache %s (%d) is mislukt: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "geen %1$s string voor %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "openen mislukte: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "kan tijdelijk bestand niet aanmaken: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "openen van tijdelijk bestand mislukte: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Tijdens het schrijven van primaire cache %s repowriter schrijven is mislukt:"
+" %i, fout: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Kan tmp-bestand %s niet sluiten: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Kan nieuw geschreven primaire cache niet gebruiken: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Kan nieuw geschreven primaire cache niet gebruiken: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "kan geen tijdelijk bestand %s aanmaken"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Tijdens het schrijven van extensiecache %s (%d): schrijven naar repowriter "
+"is mislukt: %i, fout: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"Tijdens het schrijven van extensiecache (%d): kan tijdelijk bestand niet "
+"sluiten: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Kan nieuw geschreven extensiecache niet gebruiken: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Kan nieuw geschreven extensiecache niet gebruiken: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "nul repo md bestand"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "kan bestand %1$s niet lezen: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Tijdens het laden van de repository kon %s niet worden gebruikt: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "laden van MD_TYPE_PRIMARY is mislukt."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Het openen van repository primaire data is mislukt: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Het laden van repomd is mislukt: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Het laden van primair is mislukt: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "automatisch detecteren van architectuur is mislukt"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "aanmaken van cachemap %s is mislukt"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "laden van RPMDB is mislukt"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Geen modulestandaardwaarden gevonden: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "percentage is niet 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "aantal stappen instellen mislukte: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "geannuleerd door gebruikersactie"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "klaar met toestand %1$p welke geen grootte ingesteld heeft! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "al op 100%% toestand [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Bronnen niet ingesteld bij het proberen om pakket %s te verzekeren"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Het verzekeren van %1$s mislukte omdat repo %2$s niet gevonden werd(%3$i "
+"repo's geladen)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Controleren van niet vertrouwde mislukte: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Het gedownloade bestand voor %s is niet gevonden"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"pakket %1$s kan worden geverifieerd en repo %2$s heeft GPG niet aangezet: "
+"%3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Waarde verkrijgen voor CacheDir mislukte"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Verkrijgen van vrije grootte van bestandssysteem voor %s mislukte: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Verkrijgen van vrije grootte van bestandssysteem voor %s mislukte"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Niet genoeg vrije ruimte in %1$s: %2$s is nodig, %3$s beschikbaar"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "root instellen mislukte"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Fout %i bij uitvoeren van transactietest"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Fout %i bij het openen van rpm database"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+"De dbCookie() functie heeft geen cookie van de rpm-database teruggegeven."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Fout %i bij uitvoeren van transactie"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"Transactie ging niet naar de schrijffase, maar leverde geen fout op(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "kan map %1$s niet openen: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "verwijderen van %s mislukte"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Slecht gevormde keuzeschakelaar, aanwezigheid van meerdere match-objecten in"
+" het filter"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Slecht gevormde keuzeschakelaar wordt voor de bewerking gebruikt, onjuist "
+"vergelijkingstype"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s van %s behoort niet tot een distupgrade repository"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s van %s heeft een inferieure architectuur"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "probleem met geïnstalleerd pakket "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "tegenstrijdige verzoeken"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "niet-ondersteund verzoek"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "niets levert het gevraagde "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "pakket %s bestaat niet"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " wordt geleverd door het systeem"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "een afhankelijkheidsprobleem"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "kan de beste update-kandidaat voor pakket niet installeren "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "kan de beste kandidaat voor de taak niet installeren"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "pakket %s van %s wordt uitgefilterd door modulaire filtering"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "pakket %s van %s heeft geen compatibele architectuur"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "pakket %s van %s is niet installeerbaar"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "pakket %s van %s wordt uitgefilterd door uitsluitend filteren"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "niets biedt %s welke nodig is voor %s van %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "kan niet zowel %s van %s als %s van %s installeren"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "pakket %s van %s conflicteert met %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "pakket %s van %s veroudert %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "geïnstalleerde pakket %s veroudert %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "pakket %s van %s veroudert %s aangeboden door %s van %s impliciet"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"pakket %s van %s vereist %s, maar niets van de aanbieders kan worden "
+"geïnstalleerd"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "pakket %s van %s conflicteert met %s welke het zelf aanbood"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "zowel pakket %s van %s als %s van %s verouderen %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s van %s behoort niet tot een distupgrade repository"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s van %s heeft een inferieure architectuur"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "probleem met geïnstalleerde module "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "module %s bestaat niet"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "kan de beste update-kandidaat voor module niet installeren "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "module %s van %s is uitgeschakeld"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "module %s van %s heeft geen compatibele architectuur"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "module %s van %s is niet installeerbaar"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "niets biedt %s aan welke nodig is voor module %s van %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "kan niet zowel modules %s van %s als %s van %s installeren"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "module %s van %s conflicteert met %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "module %s van %s veroudert %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "geïnstalleerde module %s veroudert %s aangeboden door %s van %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "module %s van %s veroudert %s aangeboden door %s van %s impliciet"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"module %s van %s vereist %s, maar niets van de aanbieders kan worden "
+"geïnstalleerd"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "module %s van %s conflicteert met %s welke het zelf aanbiedt"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "zowel module %s van %s als %s van %s verouderen %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "geen oplosser ingesteld"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "%s te verouderen mislukte"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "debugdata schrijven naar %1$s mislukte: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "geen oplosser in het doel"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "geen oplossing, kan beschermde pakket niet verwijderen"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "geen oplossing mogelijk"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Probleem: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Probleem %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+"De bewerking zou resulteren in het verwijderen van de volgende beveiligde "
+"pakketten: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+"Libsolv's solv_toolversion is: %zu lang maar we verwachten een maximum van: "
+"%zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Hernoemen van %1$s naar %2$s mislukte: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Instellen van rechten op %1$s mislukte: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "kan map %1$s niet aanmaken: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "kan geen stat uitvoeren op pad %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Ongeldig formaat van Platform module: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Meerdere moduleplatforms aangeboden door beschikbare pakketten\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Meerdere moduleplatforms aangeboden door geïnstalleerde pakketten\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Detectie van platformmodule in %s mislukte: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "PLATFORM_ID ontbreekt in %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Geen geldig Platform ID gedetecteerd"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Kan meerdere streams voor module '%s' niet aanzetten"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Conflicterende standaardwaarden bij repo '%s': %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Moduleprofielen installeren:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Moduleprofielen uitschakelen:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Modulestreams inschakelen:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Modulestreams omschakelen:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Modules uitschakelen:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Modules herstellen:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Kan modulaire Fail-Safe data op '%s' niet laden"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "Kan modulaire Fail-Safe data voor module niet laden '%s:%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Kan map \"%s\" voor modulaire Fail Safe data niet aanmaken: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Kan modulairr Fail Safe data niet opslaan naar '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Kan modulaire Fail Safe data in '%s' niet verwijderen"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Kan modulaire veroudering niet toepassen op '%s:%s' omdat doelmodule '%s' is"
+" uitgeschakeld"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Kan niet bijwerken vanaf string: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Kan niet oplossen: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+"Er zijn fouten opgetreden bij het oplossen van modulaire standaardwaarden: "
+"%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Kan standaardwaarden niet upgraden: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Kan streams niet upgraden: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"Kan verouderde module niet ophalen omdat er geen stream overeenkomt met "
+"%s:%s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Kan gedeelde bibliotheek \"%s\" niet laden: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Kan adres van symbool \"%s\" niet verkrijgen: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Laden van plug-in bestand=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Plug-in naam=\"%s\" geladen, versie=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath mag niet leeg zijn"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Kan plug-in map \"%s\" niet lezen: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Kan plug-in \"%s\" niet laden: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Kan tijdelijke repo-bestemmingsmap \"%s\" niet aanmaken: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Het gebruik van de '==' operator in reldeps kan resulteren in een "
+"ongedefinieerd gedrag. Het is verouderd en de ondersteuning zal in "
+"toekomstige versies worden geschrapt. Gebruik in plaats hiervan de operator "
+"'='."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Repository %s heeft geen spiegel of baseurl set."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+"Repository '%s' heeft niet-ondersteund type: 'type=%s', wordt overgeslagen."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "repo '%s': 'basecachedir' is niet ingesteld"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Maximale download snelheid is lader dan het minimum. Verander de "
+"configuratie van minrate of throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "repo '%s': 'proxy_username' is ingesteld maar niet 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' is ingesteld maar niet 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Kan geen geldige baseurl voor repo vinden: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Ophalen van GPG sleutel voor repo '%s' mislukte: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0x%s is al geïmporteerd"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Aanmaken van map \"%s\" mislukte: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: importeerde sleutel 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "vernieuwen: repo '%s' wordt overgeslagen, geen metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "vernieuwen: repo '%s' wordt overgeslagen, geen bruikbare hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "reviving: mislukte voor '%s', niet overeenkomende %s som."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"reviving: '%s' kan vernieuwd worden - metalink checksums komen overeen."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "reviving: '%s' kan vernieuwd worden - repomd komt overeen."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "reviving: mislukte voor '%s', repomd komt niet overeen."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Kan repo-bestemmingsmap \"%s\" niet aanmaken: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Kan map \"%s\" niet aanmaken: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Kan map \"%s\" niet hernoemen naar \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: cache wordt gebruikt voor: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Cache-only aangezet maar er is geen cache voor '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: downloaden opstand van: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Downloaden van metadata voor repo '%s' mislukte: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): Berekening van SHA256 mislukte"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Kan persistente map \"%s\" niet aanmaken: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"hervatten kan tegelijkertijd worden gebruikt met de byterangestart parameter"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget initialisatie mislukte: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Kan %s niet openen: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Logboekafhandelaar met id %ld bestaat niet"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Bezig"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Niet bezig"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Geen transactie bezig"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Probeer transactie-item toe te voegen in voltooide transactie"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Probeer transactie-item te updaten in voltooide transactie"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Database beschadigd: geen rij 'versie' in tabel 'config'"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: kan geschiedenis aanhoudende map niet openen"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Kan geen geschiedenisdatabase vinden"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Transactie is al begonnen!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem toestand in niet ingesteld: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Kan console-uitvoer niet toevoegen aan niet-opgeslagen transactie"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "kan sleutels niet tonen: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "oplosser toevoegen mislukte"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() kon geen data schrijven: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() kon geschreven oplosbestand niet herladen"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) is mislukt: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() is mislukt."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Kan module artefact NEVRA '%s' niet ontleden"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Slechte id voor repo: %s, byte = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "berekenen van RPMDB checksum is mislukt"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 04:27+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Oriya\n"
+"Language: or\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "ପ୍ରଗତି ପଥେ"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# A S Alam <aalam@fedoraproject.org>, 2018. #zanata
+# A S Alam <amanpreet.alam@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2021-01-24 17:38+0000\n"
+"Last-Translator: A S Alam <amanpreet.alam@gmail.com>\n"
+"Language-Team: Punjabi <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/pa/>\n"
+"Language: pa\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Weblate 4.4.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "ਕੋਈ ਮੁੱਲ ਨਹੀਂ ਦਿੱਤਾ"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "ਅਣਪਛਾਤੀ ਇਕਾਈ '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "'%s' ਫ਼ੀਸਦੀ ਹੱਦ ਤੋਂ ਬਾਹਰ ਹੈ"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "ਜਾਰੀ ਹੈ"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Piotr Drąg <piotrdrag@gmail.com>, 2011,2014,2015, 2020, 2021, 2022, 2023.
+# Piotr Drąg <piotrdrag@gmail.com>, 2016. #zanata, 2020, 2021, 2022, 2023.
+# Piotr Drąg <piotrdrag@gmail.com>, 2017. #zanata, 2020, 2021, 2022, 2023.
+# Piotr Drąg <piotrdrag@gmail.com>, 2018. #zanata, 2020, 2021, 2022, 2023.
+# Piotr Drąg <piotrdrag@gmail.com>, 2019. #zanata, 2020, 2021, 2022, 2023.
+# Piotr Drąg <piotrdrag@gmail.com>, 2020. #zanata, 2021, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-04-01 09:19+0000\n"
+"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
+"Language-Team: Polish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/pl/>\n"
+"Language: pl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nie podano wartości"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "wartość sekund „%s” nie może być ujemna"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "nie można przekonwertować „%s” na bajty"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "nieznana jednostka „%s”"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "nieprawidłowa wartość"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "wartość 1 nie jest dozwolona"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "ujemna wartość nie jest dozwolona"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "procent „%s” jest poza zakresem"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Konfiguracja: OptionBinding o identyfikatorze „%s” nie istnieje"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Konfiguracja: OptionBinding o identyfikatorze „%s” już istnieje"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "nieprawidłowa wartość logiczna „%s”"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "wartość „%s” nie jest dozwolona"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "podana wartość [%d] musi być mniejsza niż dozwolona wartość [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "podana wartość [%d] musi być większa niż dozwolona wartość [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "podana ścieżka „%s” nie jest bezwzględna."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "podana ścieżka „%s” nie istnieje."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "nie można przekonwertować „%s” na sekundy"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): nie ustawiono wartości"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Nie można włączyć więcej strumieni z modułu „%s” jednocześnie"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Nie można włączyć modułu „%1$s” strumienia „%2$s”: stan modułu został już "
+"zmodyfikowany"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Problem z modularną zależnością za pomocą domyślnych: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Problem z modularną zależnością za pomocą najnowszych modułów: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Problem z modularną zależnością: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Nie można rozwiązać parametru „%s”"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Wymagana jest tylko nazwa modułu. Ignorowanie niepotrzebnych informacji "
+"w parametrze: „%s”"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"Nie można przywrócić modułu „%s”: stan modułu został już zmodyfikowany"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Nie można wyłączyć modułu „%s”: stan modułu został już zmodyfikowany"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Brak dostępnych danych modularnych"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ignorowanie niepotrzebnych informacji w parametrze: „%s”"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Problem podczas włączania drzewa zależności dla modułu „%1$s” strumienia "
+"„%2$s”: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Wystąpiły problemy podczas żądania włączenia modułu:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+"Nie odnaleziono pakietów aktywnego modułu dla specyfikacji modułu „%s”"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Nie można zainstalować modułu „%s” z repozytorium Fail-Safe"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Nie odnaleziono profilu pasującego do „%s”"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Brak wyników dla pakietu „%s” dla specyfikacji modułu „%s”"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Problem podczas instalacji modułu „%1$s” strumienia „%2$s”: %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Wystąpiły problemy podczas żądania instalacji modułu:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Wystąpiły problemy podczas żądania przywrócenia modułu:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Wystąpiły problemy podczas żądania wyłączenia modułu:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Działanie spowodowałoby przełączenie modułu „%s” strumienia „%s” na strumień"
+" „%s”"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Przełączenie włączonych strumieni modułu jest niemożliwe.\n"
+"Zalecane jest usunięcie całej zainstalowanej treści z modułu, a następnie przywrócenie modułu za pomocą polecenia „microdnf module reset <nazwa_modułu>”. Po przywróceniu modułu można zainstalować inny strumień."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Nie można rozwiązać zależności transakcji; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "Wykryto %i problem:\n"
+msgstr[1] "Wykryto %i problemy:\n"
+msgstr[2] "Wykryto %i problemów:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problem %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problem: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Brak dostępnych modularnych metadanych dla modularnego pakietu „%s”, nie "
+"można zainstalować na komputerze"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "podpis nie jest poprawny dla %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "otwarcie się nie powiodło (ogólny błąd): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "sprawdzenie poprawności klucza dla %s się nie powiodło"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "klucz publiczny dla %s jest niedostępny"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "nie odnaleziono podpisu dla %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "dodanie elementu instalacji się nie powiodło: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Błąd podczas wykonywania transakcji: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Błąd podczas wykonywania transakcji, ale nie zgłoszono żadnych błędów."
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Błąd krytyczny, proszę wykonać przywracanie bazy danych"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "odnalezienie pakietu %s się nie powiodło"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "nie można dodać elementu usunięcia %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() się nie powiodło."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Wczytanie pamięci podręcznej rozszerzeń %s (%d) się nie powiodło: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "brak ciągu %1$s dla %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "otwarcie się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "nie można utworzyć pliku tymczasowego: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "otwarcie pliku tymczasowego się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Podczas zapisywania głównej pamięci podręcznej %s zapis repowriter się nie "
+"powiódł: %i, błąd: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Zamknięcie pliku tymczasowego %s się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+"Użycie nowo zapisanej głównej pamięci podręcznej się nie powiodło: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Użycie nowo zapisanej głównej pamięci podręcznej się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "nie można utworzyć pliku tymczasowego %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Podczas zapisywania pamięci podręcznej rozszerzeń %s (%d): zapis repowriter "
+"się nie powiódł: %i, błąd: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"Podczas zapisywania pamięci podręcznej rozszerzeń (%d): nie można zamknąć "
+"pliku tymczasowego: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+"Użycie nowo zapisanej pamięci podręcznej rozszerzeń się nie powiodło: %s "
+"(%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+"Użycie nowo zapisanej pamięci podręcznej rozszerzeń się nie powiodło: %s "
+"(%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "pusty plik md repozytorium"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "nie można odczytać pliku %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Użycie %s podczas wczytywania repozytorium się nie powiodło: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "wczytanie MD_TYPE_PRIMARY się nie powiodło."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Otwarcie głównych danych repozytorium się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Wczytanie repomd się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Wczytanie głównej się nie powiodło: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "automatyczne wykrycie architektury się nie powiodło"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "utworzenie katalogu pamięci podręcznej %s się nie powiodło"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "wczytanie bazy danych RPM się nie powiodło"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Nie odnaleziono domyślnych modułu: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "procent nie wynosi 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "ustawienie kroków liczb się nie powiodło: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "anulowane przez działanie użytkownika"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "ukończono na stanie %1$p, który nie ma ustawionego rozmiaru. [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "ma już stan 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Źródła nie są ustawione podczas próby zapewnienia pakietu %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Zapewnienie pakietu %1$s się nie powiodło, ponieważ nie odnaleziono "
+"repozytorium %2$s (wczytane repozytoria: %3$i)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Sprawdzenie niezaufanych się nie powiodło: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Nie odnaleziono pobranego pliku dla %s"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"nie można sprawdzić poprawności pakietu %1$s, a repozytorium %2$s ma "
+"włączone GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Uzyskanie wartości dla katalogu pamięci podręcznej się nie powiodło"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Uzyskanie wolnego miejsca w systemie plików dla %s się nie powiodło: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Uzyskanie wolnego miejsca w systemie plików dla %s się nie powiodło"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"Za mało wolnego miejsca na %1$s: wymagane jest %2$s, dostępne jest %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "ustawienie roota się nie powiodło"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Błąd %i podczas wykonywania testu transakcji"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Błąd %i podczas otwierania bazy danych RPM"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "Funkcja rpmdbCookie() nie zwróciła ciasteczka bazy danych RPM."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Błąd %i podczas wykonywania transakcji"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"Transakcja nie przeszła do etapu zapisu, ale nie zwróciła żadnego błędu (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "nie można otworzyć katalogu %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "usunięcie %s się nie powiodło"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Błędnie sformatowany selektor, obecność wielu obiektów dopasowania w filtrze"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Do działania użyto błędnie sformatowanego selektora, niepoprawny typ "
+"porównania"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s z %s nie należy do repozytorium distupgrade"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s z %s ma niższą architekturę"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problem z zainstalowanym pakietem "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "sprzeczne żądania"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "nieobsługiwane żądanie"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "nic nie dostarcza żądanego "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "pakiet %s nie istnieje"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " jest dostarczane przez system"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "problem zależności"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+"nie można zainstalować najlepszego kandydata aktualizacji dla pakietu "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "nie można zainstalować najlepszego kandydata do zadania"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "pakiet %s z %s został odfiltrowany filtrem modularnym"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "pakiet %s z %s nie ma zgodnej architektury"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "nie można zainstalować pakietu %s z %s"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "pakiet %s z %s został odfiltrowany filtrem wykluczania"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "nic nie dostarcza %s wymaganego przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "nie można zainstalować %s z %s i %s z %s jednocześnie"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "pakiet %s z %s jest sprzeczny z %s dostarczanym przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "pakiet %s z %s zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "zainstalowany pakiet %s zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "pakiet %s z %s niebezpośrednio zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"pakiet %s z %s wymaga %s, ale nie można zainstalować żadnego pakietu go "
+"dostarczającego"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "pakiet %s z %s jest sprzeczny z %s dostarczanym przez samego siebie"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "pakiety %s z %s i %s z %s zastępują %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s z %s nie należy do repozytorium distupgrade"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s z %s ma niższą architekturę"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "problem z zainstalowanym modułem "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "moduł %s nie istnieje"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "nie można zainstalować najlepszego kandydata aktualizacji dla modułu "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "moduł %s z %s jest wyłączony"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "moduł %s z %s nie ma zgodnej architektury"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "nie można zainstalować modułu %s z %s"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "nic nie dostarcza %s wymaganego przez moduł %s z %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "nie można zainstalować modułów %s z %s i %s z %s jednocześnie"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "moduł %s z %s jest sprzeczny z %s dostarczanym przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "moduł %s z %s zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "zainstalowany moduł %s zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "moduł %s z %s niebezpośrednio zastępuje %s dostarczane przez %s z %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"moduł %s z %s wymaga %s, ale nie można zainstalować żadnego modułu go "
+"dostarczającego"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "moduł %s z %s jest sprzeczny z %s dostarczanym przez samego siebie"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "moduły %s z %s i %s z %s zastępują %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "nie ustawiono mechanizmu rozwiązywania"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "ustawienie %s na bezwzględne się nie powiodło"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "zapisanie danych debugowania do %1$s się nie powiodło: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "brak mechanizmu rozwiązywania w celu"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "brak rozwiązania, nie można usunąć chronionego pakietu"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "brak możliwego rozwiązania"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Problem: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "%d. problem: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Działanie spowodowałoby usunięcie tych chronionych pakietów: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+"solv_toolversion biblioteki libsolv ma: %zu, kiedy oczekiwane jest maksimum:"
+" %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Zmiana nazwy %1$s na %2$s się nie powiodła: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Ustawienie uprawnień %1$s się nie powiodło: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "nie można utworzyć katalogu %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "nie można wykonać stat na ścieżce %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Nieprawidłowy format modułu platformy: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Dostępne pakiety dostarczają wiele platform modułów\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Zainstalowane pakiety dostarczają wiele platform modułów\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Wykrycie modułu platformy w %s się nie powiodło: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Brak PLATFORM_ID w %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Nie wykryto prawidłowego identyfikatora platformy"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Nie można włączyć wielu strumieni dla modułu „%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Sprzeczne domyślne z repozytorium „%s”: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Instalowanie profili modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Wyłączanie profili modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Włączanie strumieni modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Przełączanie strumieni modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Wyłączanie modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Przywracanie modułów:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Wczytanie modularnych danych Fail-Safe w „%s” się nie powiodło"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+"Wczytanie modularnych danych Fail-Safe dla modułu „%s:%s” się nie powiodło"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+"Utworzenie katalogu „%s” dla modularnych danych Fail Safe się nie powiodło: "
+"%s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Zapisanie modularnych danych Fail Safe do „%s” się nie powiodło"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Usunięcie modularnych danych Fail Safe w „%s” się nie powiodło"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Nie można zastosować modularnych zastępowań na „%s:%s”, ponieważ moduł "
+"docelowy „%s” jest wyłączony"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Zaktualizowanie z ciągu się nie powiodło: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Rozwiązanie się nie powiodło: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Wystąpiły błędy podczas rozwiązywania modułowych domyślnych: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Zaktualizowanie domyślnych się nie powiodło: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Zaktualizowanie strumieni się nie powiodło: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"Nie można pobrać zastępowań modułu, ponieważ żaden strumień nie pasuje do "
+"%s: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Nie można wczytać współdzielonej biblioteki „%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Nie można uzyskać adresu symbolu „%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Wczytywanie wtyczki file=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Wczytywanie wtyczki name=\"%s\", version=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "dirPath dla Plugins::loadPlugins() nie może być puste"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Nie można odczytać katalogu wtyczki „%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Nie można wczytać wtyczki „%s”: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Nie można utworzyć katalogu tymczasowego repozytorium „%s”: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Użycie operatora „==” w reldeps może spowodować nieokreślone zachowanie. "
+"Jest to przestarzałe i obsługa zostanie usunięta w przyszłych wersjach. "
+"Należy użyć operatora „=” zamiast tego."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+"Repozytorium %s nie ma ustawionego serwera lustrzanego ani podstawowego "
+"adresu URL."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "Repozytorium „%s” ma nieobsługiwany typ: „type=%s”, pomijanie."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "repozytorium „%s”: „basecachedir” nie jest ustawione"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Maksymalna prędkość pobierania jest mniejsza niż minimalna. Proszę zmienić "
+"konfigurację „minrate” lub „throttle”"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"repozytorium „%s”: „proxy_username” jest ustawione, ale „proxy_password” nie"
+" jest"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "„proxy_username” jest ustawione, ale „proxy_password” nie jest"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+"Nie można odnaleźć prawidłowego podstawowego adresu URL dla repozytorium: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Pobranie klucza GPG dla repozytorium „%s” się nie powiodło: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repozytorium %s: 0x%s jest już zaimportowane"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Utworzenie katalogu „%s” się nie powiodło: %d — %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repozytorium %s: zaimportowano klucz 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "odnawianie: pominięto repozytorium „%s”, brak metaodnośnika."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+"odnawianie: pominięto repozytorium „%s”, brak sumy kontrolnej możliwej do "
+"użycia."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "odnawianie: niepowodzenie dla „%s”, suma kontrolna %s się nie zgadza."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"odnawianie: można odnowić „%s” — sumy kontrolne metaodnośnika się zgadzają."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "odnawianie: można odnowić „%s” — repomd się zgadza."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "odnawianie: niepowodzenie dla „%s”, repomd się nie zgadza."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Nie można utworzyć katalogu docelowego repozytorium „%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Nie można utworzyć katalogu „%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Nie można zmienić nazwy katalogu „%s” na „%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repozytorium: używanie pamięci podręcznej dla: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Włączono tylko pamięć podręczną, ale brak pamięci podręcznej dla „%s”"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repozytorium: pobieranie z serwera: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Pobranie metadanych repozytorium „%s” się nie powiodło: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): obliczenie sumy SHA256 się nie powiodło"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Nie można utworzyć trwałego katalogu „%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "nie można używać wznawiania jednocześnie z parametrem byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Inicjacja PackageTarget się nie powiodła: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Nie można otworzyć %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Program obsługujący dziennik o identyfikatorze %ld nie istnieje"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "W trakcie wykonywania"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Nie jest w trakcie wykonywania"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Nie ma wykonywanych transakcji"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Próba wstawienia elementu transakcji do ukończonej transakcji"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Próba zaktualizowania elementu transakcji w ukończonej transakcji"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Uszkodzona baza danych: brak rzędu „version” w tabeli „config”"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: nie można otworzyć trwałego katalogu historii"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Nie można odnaleźć bazy danych historii"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Transakcja została już rozpoczęta."
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Stan TransactionItem nie jest ustawiony: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Nie można dodać wyjścia konsoli do niezapisanej transakcji"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "nie można wyświetlić listy kluczy: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "dodanie mechanizmu rozwiązywania się nie powiodło"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "zapisanie danych przez write_main() się nie powiodło: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr ""
+#~ "ponowne wczytanie zapisanego pliku mechanizmu rozwiązywania przez "
+#~ "write_main() się nie powiodło"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) się nie powiodło: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() się nie powiodło."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Przetworzenie NEVRA „%s” artefaktu modułu się nie powiodło"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Błędny identyfikator dla repozytorium: %s, bajt = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "obliczenie sumy kontrolnej bazy danych RPM się nie powiodło"
--- /dev/null
+# Joao Almeida <intjalmeida@gmail.com>, 2017. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2017-01-14 05:19+0000\n"
+"Last-Translator: Joao Almeida <intjalmeida@gmail.com>\n"
+"Language-Team: Portuguese\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nenhum valor especificado"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "o segundo valor '%s' não pode ser negativo"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unidade desconhecida '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+#, fuzzy
+#| msgid "'%s' is not an allowed value"
+msgid "value 1 is not allowed"
+msgstr "o valor '%s' não é permitido"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "a percentagem '%s' está fora do intervalo"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valor de booleano inválido '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "o valor '%s' não é permitido"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "valor dado [%d] deve ser menor do que o valor permitido [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "valor dado [%d] deve ser maior do que o valor permitido [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "o caminho dado '%s' não é absoluto."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "o caminho dado '%s' não existe."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Em curso"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Daniel Lara <danniel@fedoraproject.org>, 2016. #zanata
+# Bruno Furtado <bffurtado@gmail.com>, 2017. #zanata
+# Daniel Lara <danniel@fedoraproject.org>, 2017. #zanata
+# Frederico Henrique Gonçalves Lima <fred@fredericolima.com.br>, 2017. #zanata
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Fábio Rodrigues Ribeiro <farribeiro@gmail.com>, 2020, 2021.
+# Gustavo Costa <gusta@null.net>, 2020.
+# Henrique Roberto Gattermann Mittelstaedt <henrique.roberto97@gmail.com>, 2020.
+# Gustavo Costa <xfgusta@gmail.com>, 2021.
+# Daimar Stein <daimarstein@pm.me>, 2022, 2023.
+# Ian Meyer <ianscuba1465@gmail.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-05-28 14:20+0000\n"
+"Last-Translator: Ian Meyer <ianscuba1465@gmail.com>\n"
+"Language-Team: Portuguese (Brazil) <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/pt_BR/>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Weblate 4.17\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "nenhum valor especificado"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "valor de segundos '%s' não deve ser negativo"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "não foi possível converter '%s' para bytes"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "unidade desconhecida '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "valor inválido"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "valor 1 não é permitido"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "valor negativo não é permitido"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "porcentagem '%s' está fora do intervalo"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Configuração: OptionBinding com id \"%s\" não existe"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Configuração: OptionBinding com id \"%s\" já existe"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "valor booleano inválido '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' não é um valor permitido"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "valor dado [%d] deveria ser menor que o valor permitido [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "valor dado [%d] deveria ser maior que o valor permitido [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "caminho informado '%s' não é absoluto."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "caminho informado '%s' não existe."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "não foi possível converter '%s'para segundos"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): valor não definido"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Não é possível habilitar mais fluxos do módulo '%s' ao mesmo tempo"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, fuzzy, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Não é possível habilitar o módulo '%1$s' stream '%2$s': Estado do módulo já "
+"modificado"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Problema de dependência modular com os padrões: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Problema de dependência modular com os módulos mais recentes: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Problema de dependência modular: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Não foi possível resolver o argumento '%s'"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Somente o nome do módulo é necessário. Ignorando informações desnecessárias "
+"no argumento: '%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"Não é possível resetar módulo '%s': Estado do módulo já foi modificado"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Não pode desabilitar módulo '%s': Estado do módulo já modificado"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Nenhum dado modular disponível"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ignorando informação desnecessária no argumento: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Problema durante a ativação da árvore de dependências para o fluxo do módulo"
+" '%1$s' de '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Apareceram problemas para a solicitação de ativação do módulo:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Nenhum pacote de módulo ativo encontrado para spec de módulo '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+"Não é possível instalar o módulo '%s' através do repositório de segurança"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Nenhum perfil encontrado que corresponde a '%s'"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Nenhuma correspondência para o pacote '%s' para o spec de módulo %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Problema durante a instalação do módulo '%1$s' do fluxo '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Apareceram problemas para a solicitação de instalação do módulo:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Apareceram problemas para a solicitação de redefinição do módulo:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Apareceram problemas para a solicitação de desativação do módulo:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"A operação resultaria na mudança do módulo '%s' do fluxo '%s' para o '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+#, fuzzy
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Não é possível alternar fluxos ativados de um módulo.\n"
+"É recomendável remover todo o conteúdo instalado do módulo e redefinir o módulo usando o comando '{prog} module reset <nome_do_módulo>'. Depois de redefinir o módulo, você pode instalar o outro fluxo."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Não foi possível resolver as dependências da transação; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i problema detectado:\n"
+msgstr[1] "%i problemas detectados:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problema %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problema: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Nenhum metadado modular disponível para o pacote modular '%s'; não pode ser "
+"instalado no sistema"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "assinatura não verifica para %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "Falha ao abrir (erro genérico): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "Falha ao verificar chave para %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "chave pública indisponível para %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "assinatura não encontrada para %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "Falha ao adicionar o elemento de instalação: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Erro ao executar a transação: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "Erro ao executar a transação e nenhum problema foi relatado!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Erro fatal, execute a recuperação do banco de dados"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "não encontrou o pacote %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "não foi possível adicionar o elemento apagar %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv () falhou."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "nenhuma string %1$s para %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "falhou para abrir: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "não é possível criar um arquivo temporário: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "Falha ao abrir o arquivo tmp: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Falha ao fechar o arquivo tmp %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "não pode criar um arquivo temporário %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "arquivo nulo repo md"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "não consigo ler o arquivo %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "o carregamento de MD_TYPE_PRIMARY falhou."
+
+#: libdnf/dnf-sack.cpp:784
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Opening repository primary data has failed: %s"
+msgstr "Carregando arquivo plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:795
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading repomd has failed: %s"
+msgstr "Carregando arquivo plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:806
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading primary has failed: %s"
+msgstr "Carregando arquivo plugin=\"%s\""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "Falha ao detectar automaticamente a arquitetura"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "Falha ao criar o Cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "falha ao carregar o RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Nenhum padrão de módulo encontrado: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "percentagem não 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "Falha ao definir etapas numéricas: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "cancelado pela ação do usuário"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "feito em um estado %1$p que não tinha um tamanho definido! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "já em 100 %% state [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Fontes não definidas ao tentar garantir o pacote %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Não foi possível garantir %1$s como repo %2$s não encontrado(%3$i repos "
+"carregados)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Falha ao verificar não confiável: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Arquivo baixado para %s não encontrado"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"pacote %1$s não pode ser verificado e repo %2$s está habilitado para GPG: "
+"%3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Falha ao obter valor para CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Falha ao obter tamanho livre do sistema de arquivos para %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Falha ao obter tamanho livre do sistema de arquivos para %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Não há espaço livre suficiente %1$s: necessário %2$s, acessível %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "não conseguiu definir raiz"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Erro %i executando o teste de transação"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Erro %i transação em execução"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"A transação não foi para a fase de escrita, mas não retornou nenhum erro "
+"(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "não pode abrir o diretório %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "não foi possível remover %s"
+
+#: libdnf/goal/Goal.cpp:78
+#, fuzzy
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Seletor malformado, presença de vários objetos de correspondência no filtro"
+
+#: libdnf/goal/Goal.cpp:79
+#, fuzzy
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Seletor malformado usado para a operação, tipo de comparação incorreto"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "não pertence a um repositório distupgrade"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "tem arquitetura inferior"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problema com o pacote instalado "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "solicitações conflitantes"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "solicitação não suportada"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "nada fornece o solicitado "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "o pacote %s não existe"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " é fornecido pelo sistema"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "algum problema de dependência"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+"não é possível instalar o melhor candidato à atualização para o pacote "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "não é possível instalar o melhor candidato para a tarefa"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "o pacote %s é filtrado por filtragem modular"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "o pacote %s não possui uma arquitetura compatível"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "pacote %s não é instalável"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "o pacote %s é filtrado pela filtragem de exclusão"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "nada fornece %s necessário para %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "não é possível instalar %s e %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "pacote %s conflita com %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "pacote %s torna obsoleto %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "pacote instalado %s torna obsoleto %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "o pacote %s torna obsoleto implicitamente %s fornecido por %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "pacote %s requer %s, mas nenhum dos provedores pode ser instalado"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "pacote %s conflita com %s oferecido por si mesmo"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "ambos os pacotes %s e %s tornam obsoleto %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "não pertence a um repositório distupgrade"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "tem arquitetura inferior"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "problema com módulo instalado "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "módulo %s não existe"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+"não é possível instalar o melhor candidato de atualização para o módulo "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "módulo %s está desabilitado"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "módulo %s não possui uma arquitetura compatível"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "módulo %s não é instalável"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "nada fornece %s necessário para o módulo %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "não é possível instalar ambos os módulos %s e %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "módulo %s conflita com %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "módulo %s torna obsoleto %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "módulo instalado %s torna obsoleto %s oferecido por %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "o módulo %s torna obsoleto implicitamente %s fornecido por %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "módulo %s requer %s, mas nenhum dos provedores pode ser instalado"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "módulo %s conflita com %s oferecido por si mesmo"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "ambos os módulos %s e %s tornam obsoleto %s"
+
+#: libdnf/goal/Goal.cpp:1168
+#, fuzzy
+msgid "no solver set"
+msgstr "nenhum solucionador definido"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "falha em tornar %s absoluto"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "falha ao gravar debugdata em %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "sem solução, não é possível remover pacote protegido"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "sem solução possível"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Problema: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Problema %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "A operação resultaria na remoção dos seguintes pacotes protegidos: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Falha ao renomear %1$s para %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Falha ao definir permissões em %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "não é possível criar o diretório %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "não foi possível obter stat do caminho %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Formato inválido da Plataforma do módulo: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Múltiplas plataformas de módulo oferecidas pelos pacotes disponíveis\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Múltiplas plataformas de módulo oferecidas pelos pacotes instalados\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Detecção do Módulo de Plataforma em %s falhou: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "PLATFORM_ID faltando em %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Nenhum ID de Plataforma válido detectado"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Instalando perfis de módulo:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Desativando perfis de módulo:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Falha em resolver: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Não é possível carregar biblioteca compartilhada \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Não é possível obter o endereço do símbolo \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Carregando arquivo plugin=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Plugin carregado nome=\"%s\", versão=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath não pode estar vazio"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Não é possível ler o diretório do plugin \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Não é possível carregar o plugin \"%s\": %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Não é possível criar o diretório temporário do repositório \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Repositório %s não possui espelho ou baseurl definido."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "O repositório '%s' tem um tipo não suportado: 'type=%s', pulando."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"A velocidade máxima de download é menor que a mínima. Por favor altere a "
+"configuração de minrate ou throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Impossível encontrar uma baseurl válida para o repo: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Falha ao recuperar a chave GPG para o repo. '%s': %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "repo %s: 0 x%s já importado"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Falha ao criar o diretório \"%s\": %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "repo %s: chave importada 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "reativando: repo '%s' ignorado, sem metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "reativando: repo '%s' ignorado, nenhum hash utilizável."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "reativando: falhou por '%s', checksum %s não coincide."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr "reativando: '%s' pode ser reativado - checksum do metalink coincide."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "reativando: '%s' pode ser reativado - repomd coincide."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "reativando: falhou por '%s', repomd não coincide."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Não foi possível criar o diretório de destino do repo \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Não é possível criar o diretório \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Não é possível renomear o diretório \"%s\" para \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: utilizando cache para: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Cache-only habilitado mas sem cache para '%s'"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: download do controle remoto: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Falha ao baixar os metadados do repo. '%s': %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir (): Falha na computação de SHA256"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Não foi possível criar persistdir \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"currículo não pode ser usado simultaneamente com o parâmetro byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Falha na inicialização do PackageTarget: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Não pode abrir %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Manipulador de log com id %ld não existe"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Em andamento"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Não em progresso"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Nenhuma transação em andamento"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Tentativa de inserir um item de transação na transação concluída"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Tentativa de atualizar o item de transação na transação concluída"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformador: não é possível abrir o histórico persistir dir"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Não foi possível encontrar um banco de dados de histórico"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "A transação já começou!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "O estado TransactionItem não está definido: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Não é possível adicionar saída do console a transação não salva"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "não pode listar chaves: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "não conseguiu adicionar solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main () falhou ao gravar dados: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main () falhou ao recarregar um arquivo resolvido por escrito"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) falhou: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml / rpmmd () falhou."
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "Falha ao calcular a soma de verificação do RPMDB"
--- /dev/null
+# Igor Gorbounov <igor.gorbounov@gmail.com>, 2017. #zanata, 2020, 2021.
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Petr Molodyk <pamolodyk@gmail.com>, 2020.
+# Vladyslav Spirin <vladspirin@hotmail.com>, 2020.
+# Alexey Rubtsov <rushills@gmail.com>, 2021, 2022.
+# V I <xasertop@gmail.com>, 2022.
+# Vi <xasertop@gmail.com>, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-01-19 14:20+0000\n"
+"Last-Translator: Vi <xasertop@gmail.com>\n"
+"Language-Team: Russian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/ru/>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.15.1\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "не указано значение"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "значение для секунд «%s» не должно быть отрицательным"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "не удалось преобразовать «%s» к байтам"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "неизвестная единица «%s»"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "неверное значение"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "значение 1 недопустимо"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "отрицательное значение недопустимо"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "процентная величина «%s» вне диапазона"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Конфигурация: OptionBinding с идентификатором \"%s\" не существует"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Конфигурация: OptionBinding с идентификатором \"%s\" уже существует"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "недопустимое логическое значение «%s»"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "«%s» не является допустимым значением"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "данное значение [%d] должно быть меньше допустимого значения [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "данное значение [%d] должно быть больше допустимого значения [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "данный путь «%s» не является абсолютным."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "данный путь «%s» не существует."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "не удалось преобразовать «%s» в секунды"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue (): значение не установлено"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Невозможно одновременно открыть дополнительные потоки из модуля «%s»"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Невозможно открыть поток «%2$s» модуля «%1$s»: модуль уже в изменённом "
+"состоянии"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Проблема с модульными зависимостями в Defaults: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Проблема с зависимостями в последних модулях: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Проблема с зависимостями модулей: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Не удалось разрешить аргумент «%s»"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Требуется только имя модуля. Игнорируется ненужная информация в аргументе: "
+"«%s»"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "Не удалось сбросить модуль «%s»: состояние модуля уже изменено"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Не удалось отключить модуль «%s»: состояние модуля уже изменено"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Нет модульных данных"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Игнорирую ненужную информацию в аргументе: «%s»"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Проблема с разрешением дерева зависимостей для модуля «%1$s» поток "
+"«%2$s»:%3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "При разрешении модуля возникли проблемы:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Не найдено активных пакетов для модуля специфицированного как «%s»"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+"Не удалось инсталлировать модуль «%s» из защищённого от ошибок репозитория"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Не найдено подходящего профиля «%s»"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+"Не найдено совпадений для пакета «%s» для модуля специфицированного как %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Проблема при установке модуля «%1$s» поток «%2$s»:%3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Проблемы, возникшие при запросе на установку модуля:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Проблемы, возникшие при запросе на сброс модуля:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Возникли проблемы при запросе отключения модуля:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Операция приведёт к переключению модуля «%s» потока «%s» на поток «%s»"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Невозможно переключить включённые потоки модуля.\n"
+"Рекомендуется удалить из модуля всё установленное и обновить модуль с помощью команды «microdnf module reset <имя_модуля>». После обновления модуля можно установить другой поток."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Не удалось отменить транзакцию; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i проблема обнаружена:\n"
+msgstr[1] "%i проблемы обнаружено:\n"
+msgstr[2] "%i проблем обнаружено:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Проблема %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Проблема: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Нет доступных мета-данных для модульного пакета «%s»; невозможно установить "
+"в систему"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "не проверена подпись для %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "не удалось открыть ( общая ощибка): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "не удалось проверить ключ для %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "публичный ключ недоступен для %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "подпись не найдена для %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "не удалось добавить элемент установки: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Ошибка при выполнении транзакции: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Возникла ошибка при исполнении транзакции, но не было зафиксировано проблем!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Фатальная ошибка, запустите восстановление базы данных"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "не удалось найти пакет %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "не удалось добавить элемент стирания %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "вызов repo_add_solv() не удался."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Ошибка загрузки кеша расширений %s (%d): "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "нет строки %1$s для %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "не удалось открыть: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "не удается создать временный файл: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "не удалось открыть файл tmp: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"При записи первичного кеша %s произошла ошибка записи в программе записи "
+"отчёта: %i, ошибка: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Не удалось закрыть временный файл %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Не удалось использовать вновь записанный первичный кеш: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Не удалось использовать вновь записанный первичный кеш: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "не удается создать временный файл %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"При записи кеша расширений %s (%d): сбой программы записи отчётов: %i, "
+"ошибка: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"При записи кеша расширений (%d): невозможно закрыть временный файл: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Не удалось использовать вновь записанный кеш расширений: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Не удалось использовать вновь записанный кеш расширений: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "файл md пустого репозитория null"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "не удается прочитать файл %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "При загрузке репозитория не удалось использовать %s: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "загрузка MD_TYPE_PRIMARY не удалась."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Не удалось открыть первичные данные репозитория: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Не удалось загрузить repomd: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Первичная загрузка не удалась: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "не удалось автоматически определить архитектуру"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "не удалось создать cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "не удалось загрузить RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Настройки модуля по умолчанию не найдены: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "процент не 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "не удалось установить количество шагов: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "отменено действием пользователя"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "сделано в состоянии %1$p у которого не было набора размеров! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "уже в состоянии 100 %% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Источники не установлены при попытке обеспечить пакет %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Не удалось обеспечить %1$s как репо %2$s не найдено(%3$i загружены "
+"репозитории)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Не удалось проверить недоверенность: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Загруженный файл для %s не найден"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "пакет %1$s не могут быть проверены и репо %2$s включен GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Не удалось получить значение для CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Не удалось получить свободный размер файловой системы для %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Не удалось получить размер файловой системы для %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Недостаточно свободного места в %1$s: необходимо %2$s, доступно %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "не удалось установить корень"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "ошибка %i проверка транзакции"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Ошибка %i при открытии базы данных rpm"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "Функция dbCookie() не вернула куки базы данных rpm."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "ошибка %i выполняемая транзакция"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "Транзакция не перешла на этап написания, но не вернула ошибку (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "не удается открыть каталог %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "не удалось удалить %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Неправильно сформированный Selector, наличие нескольких совпадающих объектов"
+" в фильтре"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Для операции использовался неправильно сформированный Selector, неправильный"
+" тип сравнения"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "не относится к хранилищу обновлений дистрибутива"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "относится к плохой архитектуре"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "проблема с установленным пакетом "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "противоречивые запросы"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "неподдерживаемый запрос"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "ничего из пакетов не содержит запрашиваемого "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "пакет %s не существует"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " предоставляется системой"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "некоторая проблема с зависимостями"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "не удалось установить лучший вариант обновления для пакета "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "не удаётся установить лучший вариант для этой задачи"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "пакет %s отфильтрован модульным фильтрованием"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "пакет %s не имеет совместимой архитектуры"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "пакет %s непригодный для установки"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "пакет %s отфильтровано при помощи фильтрации исключения"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "не содержится ничего из %s необходимого для %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "невозможно установить %s совместно с %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "пакет %s конфликтирует с %s предоставляемый %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "пакет %s делает устаревшим %s который предоставляется %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+"установленный пакет %s делает устаревшим пакет %s который предоставляется %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "пакет %s неявно заменяет пакет %s предоставляемый %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"пакету %s требуется %s, но ни один из предоставляющих пакетов не может быть "
+"установлен"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "пакет %s конфликтирует с пакетом %s предоставляемый сам собой"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "оба пакета %s и %s делают устаревшим %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "не относится к хранилищу обновлений дистрибутива"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "относится к плохой архитектуре"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "проблема с установленным модулем "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "модуль %s отсутствует"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "не удалось установить лучший вариант обновления для модуля "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "модуль %s отключён"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "для модуля %s нет совместимой архитектуры"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "модуль %s непригодный для установки"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "не предоставляется %s необходимый для модуля %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "невозможна одновременная установка модулей %s и %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "модуль %s конфликтирует с %s, предоставленный %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "модуль %s делает устаревшим модуль %s предоставляемый %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+"установленный модуль %s делает устаревшим модуль %s предоставляемый %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "модуль %s неявным способом делает устаревшим %s предоставляемый %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"модулю %s требуется %s, но ни один из предоставляющих пакетов не может быть "
+"установлен"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "модуль %s конфликтует с %s, предоставленным самим пакетом"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "оба модуля %s и %s делают устаревшим %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "нет механизма решения"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "не удалось сделать %s абсолютным"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "не удалось записать отладочные данные в %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "нет solv в цели"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "нет решения, невозможно удалить защищенный пакет"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "решение невозможно"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Проблема: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Проблема %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Операция приведёт к удалению следующих защищенных пакетов: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "solv_toolversion в Libsolv: %zu длинный, но мы ожидаем максимум: %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Не удалось переименовать %1$s в %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Не удалось установить права доступа на %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "на удается создать каталог %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "не удется выполнить stat для пути %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "неправильный формат модуля платформы: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Имеющиеся пакеты предоставляют несколько платформ модулей\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Несколько модульных платформ, предоставляемых установленными пакетами\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Не удалось обнаружение модуля платформы в %s: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Отсутствует PLATFORM_ID в %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Допустимый идентификатор платформы не обнаружен"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Не удалось активировать несколько потоков для модуля «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Конфликт параметров по умолчанию для репозитория «%s»: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Установка профилей модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Отключение профилей модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Включение потоков модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Переключение потоков модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Отключение модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Сброс модулей:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Не удалось загрузить модульные безопасные данные в «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "Не удалось загрузить модульные безопасные данные для модуля «%s:%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Не удается создать каталог «%s» для модульных безопасных данных: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Не удается загрузить модульные безопасные данные в «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Не удается удалить модульные безопасные данные в «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Не удается применить устаревшие возможности модуля к «%s:%s», потому что "
+"целевой модуль «%s» отключен"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Не удалось обновить из строки: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Не удалось разрешить: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Были ошибки при разрешении модульных параметров по умолчанию: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Не удалось обновить параметры по умолчанию: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Не удалось обновить потоки: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"Не удается получить устаревшие возможности модуля, потому что нет "
+"соответствия потока %s: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Не удается загрузить разделяемую библиотеку «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Не удается получить адрес символа «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Загрузка файла дополнения=«%s»"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Имя загруженного модуля=«%s», версия=«%s»"
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath не может быть пустым"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Не читается каталог дополнения «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Не загружается дополнение «%s»: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Невозможно создать временный каталог репо \"%s«: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Использование оператора «==» в reldeps может привести к неопределенному "
+"поведению. Он устарел и его поддержка будет прекращена в будущих версиях. "
+"Используйте вместо этого оператор «=»."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Для репозитория %s не заданы зеркала или baseurl."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "У репозитория «%s» неподдерживаемый тип: «type=%s», пропускается."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "репозиторий «%s»: не установлен «basecachedir»"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Максимальная скорость загрузки ниже минимальной. Измените конфигурацию "
+"minrate или throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "репозиторий «%s»: настроен «proxy_username», но не «proxy_password»"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "настроен «proxy_username», а не «proxy_password»"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Не удается найти правильный baseurl для репозитория: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Не удалось получить ключ GPG для репозитория «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "репозиторий %s: 0x%s уже импортирован"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Не удалось создать каталог «%s»: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "репозиторий %s: импортирован ключ 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "восстановление: репозиторий «%s» игнорируется, нет метассылок."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+"восстановление: репозиторий «%s» игнорируется, нет пригодного хэш-кода."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "восстановление: не удалось для «%s», сумма %s не совпадает."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"восстановление: «%s» может быть восстановлен - контрольные суммы метассылок "
+"совпадают."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+"восстановление: «%s» может быть восстановлен - совпадают метаданные "
+"репозитория."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+"восстановление: не удалось для «%s», не совпадают метаданные репозитория."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Не создается каталог назначения репозитория «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Невозможно создать каталог \"%s«: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Невозможно переименовать каталог «%s» в «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "репозиторий: используется кэш для: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Включён режим только кэш, но нет кэша для «%s»"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "РЕПО: загрузка с удаленного устройства: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Не удалось загрузить метаданные для репозитория «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir (): вычисление SHA256 не выполнено"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Не создается постоянный каталог «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+"резюме не может использоваться одновременно с параметром byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Не удалось инициализировать PackageTarget: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Невозможно открыть %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Обработчик журнала с идентификатором %ld не существует"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "В процессе"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Не выполняется"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Никаких транзакций"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Попытка вставить элемент транзакции в завершенную транзакцию"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Попытка обновить элемент транзакции в завершенной транзакции"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "База данных повреждена: нет строки «version» в таблице «config»"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Трансформатор: невозможно открыть историю сохранения"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Не удалось найти базу данных истории"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Транзакция уже началась!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Состояние TransactionItem не установлено: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Не удается добавить вывод консоли в несохраненную транзакцию"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "не может перечислить ключи: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "не удалось добавить solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main () не удалось записать данные: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() fне удалось перезагрузить файл solv"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) выдал ошибку: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() завершился ошибкой."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Не удалось сделать разбор артефакта модуля NEVRA: «%s»"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "не удалось вычислить контрольную сумму RPMDB"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Hela Basa <r45xveza@pm.me>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2021-08-19 06:05+0000\n"
+"Last-Translator: Hela Basa <r45xveza@pm.me>\n"
+"Language-Team: Sinhala <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/si/>\n"
+"Language: si\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: Weblate 4.7.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "වලංගු නොවන අගයකි"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+msgstr[1] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:05+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Slovak\n"
+"Language: sk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Prebieha"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:13+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Albanian\n"
+"Language: sq\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Në ecje e sipër"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:17+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Serbian\n"
+"Language: sr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "У току"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:25+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Serbian (LATIN)\n"
+"Language: sr@latin\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "U toku"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Göran Uddeborg <goeran@uddeborg.se>, 2016. #zanata, 2020, 2021, 2022.
+# Göran Uddeborg <goeran@uddeborg.se>, 2017. #zanata, 2020, 2021, 2022.
+# Göran Uddeborg <goeran@uddeborg.se>, 2018. #zanata, 2020, 2021, 2022.
+# Mikael Granberg <mikael@famgra.se>, 2020.
+# Vilhelm Prytz <vilhelm@prytznet.se>, 2020.
+# Luna Jernberg <bittin@reimu.nl>, 2021, 2022, 2023.
+# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-04-05 02:20+0000\n"
+"Last-Translator: Luna Jernberg <bittin@reimu.nl>\n"
+"Language-Team: Swedish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/sv/>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "inget värde angivet"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "sekundvärdet ”%s” får inte vara negativt"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "kunde inte konvertera ”%s” till byte"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "okänd enhet ”%s”"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "ogiltigt värde"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "värdet 1 är inte tillåtet"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "negativt värde är inte tillåtet"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "procentsatsen ”%s” är utanför intervallet"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Konfiguration: OptionBinding med id ”%s” finns inte"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Konfiguration: OptionBinding med id ”%s” finns redan"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "felaktigt booleskt värde ”%s”"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "”%s” är inte ett tillåtet värde"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+"det angivna värdet [%d] skall vara mindre än det tillåtna värdet [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+"det angivna värdet [%d] skall vara större än det tillåtna värdet [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "den angivna sökvägen ”%s” är inte absolut."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "den angivna sökvägen ”%s” finns inte."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "kunde inte konvertera ”%s” till sekunder"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Värdet är inte satt"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+"Det går inte att aktivera flera strömmar från modulen ”%s” på samma gång"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Det går inte att aktivera modulen ”%1$s” strömmen ”%2$s”: tillståndet på "
+"modulen är redan ändrat"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Modulärt beroendeproblem med standard: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Modulärt beroendeproblem med de senaste modulerna: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Modulärt beroendeproblem: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Kan inte slå upp argumentet ”%s”"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Endast modulnamn behövs. Ignorerar onödig information i argumentet: ”%s”"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+"Det går inte att återställa modulen”%s”: tillståndet på modulen är redan "
+"ändrat"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+"Det går inte att avaktivera modulen”%s”: tillståndet på modulen är redan "
+"ändrat"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Inga modulära data gilltängliga"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ignorerar onödig information i argumentet: ”%s”"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Problem under aktivering av beroendeträdet för modulen ”%1$s” strömmen "
+"”%2$s”: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Problem uppstod för modulaktiveringsbegäran:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Inga aktiva modulpaket hittade för modul spec '%s'"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Det går inte att installera modulen ”%s” från ett felsäkert förråd"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Ingen profil hittades som matchar '%s'"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Ingen matchning för paket '%s för modul spec %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Problem under installering för modul '%1$s' ström '%2$s': %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Problem uppstod för modul installationsbegäran:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Problem uppstod för modulåterställningsbegäran:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Problem uppstod för modulinaktiveringsbegäran:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Åtgärden skulle resultera i byte av modulen ”%s” ström ”%s” till ström ”%s”"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Det är inte möjligt att byta aktiverade strömmar för en modul.\n"
+"Det är rekommenderat att ta bort allt innehåll från modulen, och återställa modulen med kommandot ”dnf module reset <modulnamn>”. Efter att du återställt modulen kan du installera den andra strömmen."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Kunde inte hitta transaktionsberoende "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i problem upptäcktes:\n"
+msgstr[1] "%i problem upptäcktes:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Problem %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Problem: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Inga modulära metadata tillgängliga för det modulära paketet ”%s”; kan inte "
+"installeras på systemet"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "signaturen stämmer inte för %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "misslyckades att öppna (allmänt fel): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "misslyckades att verifiera nyckeln för %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "den publika nyckeln är inte tillgänglig för %s"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "signaturen hittades inte för %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "misslyckades att lägga till installationselement: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Fel när transaktionen kördes: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "Fel när transaktionen kördes och inga problem rapporterades!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Ödesdigert fel, kör återställning av databasen"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "misslyckades att hitta paketet %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "kunde inte lägga till borttagningselement %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() har misslyckats."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Laddar tilläggscache %s (%d) misslyckades: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "ingen %1$s sträng för %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "misslyckades att öppna: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "kan inte skapa temporärfil: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "misslyckades att öppna temporärfil: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"När den primära cachen %s skrevs misslyckades en repowriter-skrivning: %i, "
+"fel: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Misslyckades att stänga temporärfil %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Misslyckades att använda en nyss skriven primärcache: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Misslyckades att använda en nyss skriven primärcache: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "kan inte skapa den temporära filen %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"När utökningscachen %s (%d) skrevs: en repowriter-skrivning misslyckades: "
+"%i, fel: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr "När utökningscachen (%d) skrevs: kan inte stänga temporärfilen: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Misslyckades med att använda nyskriven tilläggscache: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Misslyckades med att använda nyskriven tilläggscache: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo-md-fil"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "kan inte läsa filen %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "När förrådet lästes in misslyckades att använda %s: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "Kunde inte ladda MD_TYPE_PRIMARY."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Öppning av förråd primärdata misslyckades: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Att läsa in repomd misslyckades: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Att läsa in den primära misslyckades: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "misslyckades att automatdetektera arkitekturen"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "misslyckades att skapa cache-katalogen %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "misslyckades att läsa in RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Inga standardmoduler funna: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "procentsatsen inte 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "misslyckades att sätta antal steg: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "inställt enligt användares åtgärd"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "klar i tillstånd %1$p som inte hade en storlek satt! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "reda i 100 %%-tillstånd [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Källor inte angivna vid försök att säkerställa paketet %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Misslyckades att säkerställa %1$s eftersom förrådet %2$s inte finns (%3$i "
+"förråd inlästa)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Misslyckades att kontrollera ej betrodda: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Den hämtade filen för %s finns inte"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"paketet %1$s kan inte verifieras och förrådet %2$s är GPG-aktiverat: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Misslyckades att få värdet för CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Misslyckades att ta reda på filsystemets fria utrymme för %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Misslyckades att ta reda på filsystemets fria utrymme för %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+"Inte tillräckligt med fritt utrymme i %1$s: %2$s behövs, %3$s är "
+"tillgängligt"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "misslyckades att sätta roten"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Fel %i när transaktionstesten kördes"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Fel %i vid öppnande av rpm-databas"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+"Funktionen rpmdbCookie() returnerade inte någon kaka från rpm-databasen."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Fel %i när transaktionen kördes"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "Transaktionen kom inte till skrivfasen, men returnerade inget fel(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "kan inte öppna katalogen %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "misslyckades att ta bort %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "Felformad väljare, det finns flera matchningsobjekt i filtret"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "Felformulerad väljare använd för åtgärden, felaktig jämförelsetyp"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s från %s tillhör inte något dist-uppgraderingsförråd"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s från %s har underarkitektur"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "problem med installerat paket "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "begäranden i konflikt"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "begäran som ej stödjs"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "inget tillhandahåller begärda "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "paketet %s finns inte"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " tillhandahålls av systemet"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "något beroendeproblem"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+"det går inte att installera den bästa uppdateringskandidaten för paketet "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "det går inte att installera den bästa kandidaten för jobbet"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "paket %s från %s är utfiltrerat av modulfiltrering"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "paket %s från %s har inte en kompatibel arkitektur"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "paket %s från %s är inte installerbart"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "paket %s från %s är utfiltrerat av uteslutningsfiltrering"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "inget tillhandahåller %s som behövs av %s från %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "det går inte att installera både %s från %s och %s från %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+"paket %s från %s står i konflikt med %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "paket %s från %s fasar ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "installerade paketet %s fasar ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"paket %s från %s fasar implicit ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"paket %s från %s kräver %s, men ingen av leverantörerna kan installeras"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+"paketet %s från %s står i konflikt med %s som det tillhandahåller själv"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "både paketet %s från %s och %s från %s fasar ut %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s från %s tillhör inte något dist-uppgraderingsförråd"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s från %s har underarkitektur"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "problem med den installerade modulen "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "modulen %s finns inte"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+"det går inte att installera den bästa uppdateringskandidaten för modulen "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "modul %s från %s är avaktiverad"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "modul %s från %s har inte en kompatibel arkitektur"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "modul %s från %s är inte installerbar"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "ingenting tillhandahåller %s som behövs av modulen %s från %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "det går inte att installera båda modulerna %s från %s och %s från %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+"modul %s från %s står i konflikt med %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "modul %s från %s fasas ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+"den installerade modulen %s fasar ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"modul %s från %s fasar implicit ut %s som tillhandahålls av %s från %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"modul %s från %s behöver %s, men ingen av leverantörerna kan installeras"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "modul %s från %s står i konflikt med %s som den tillhandahåller själv"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "både modulen %s från %s och %s från fasar ut %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "ingen lösare angiven"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "misslyckades att göra %s absolut"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "misslyckades att skriva felsökningsdata till %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "ingen lösning i målet"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "ingen lösning, kan inte ta bort skyddat paket"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "ingen lösning möjlig"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Problem: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Problem %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Åtgärden skulle resultera i att ta bort följande skyddade paket: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Libsolvs solv_toolversion är: %zu lång men vi förväntar oss max: %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Misslyckades att byta namn på %1$s till %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Misslyckades att sätta rättigheter på %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "kan inte skapa katalogen %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "kan inte ta status på sökvägen %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Felaktigt format på plattformsmodulen: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Flera modulplattformar tillhandahålls av tillgängliga paket\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Flera modulplattformar tillhandahålls av installerade paket\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Detektering av plattformsmodul i %s misslyckades: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Saknad PLATFORM_ID i %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Inget giltigt plattforms-ID detekterat"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Det går inte att aktivera multipla strömmar för modulen ”%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Standardvärden i konflikt med förrådet ”%s”: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Installerar modulprofiler:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Avaktiverar modulprofiler:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Aktiverar modulströmmar:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Byter modulströmmar:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Avaktiverar moduler:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Återställer moduler:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Kan inte läsa in modulär felsäker data vid ”%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "Kan inte läsa in modulär felsäker data för modulen ”%s:%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Det går inte att skapa katalogen ”%s” för modulär felsäker data: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Kan inte spara modulär felsäker data till ”%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Kan inte ta bort modulär felsäker data i ”%s”"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Kan inte verkställa modulära föråldranden på ”%s:%s” för att målmodulen ”%s”"
+" är avaktiverad"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Misslyckades att uppgradera från en sträng: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Misslyckades att slå upp: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Fel uppstod när modulstandarder löstes upp: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Misslyckades att uppgradera standardvärden: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Misslyckades att uppgradera strömmar: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr "Kan inte hämta modulutfasningar eftersom ingen ström matchar %s: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Kan inte ladda det delade biblioteket ”%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Kan inte få adressen till symbolen ”%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Läser in insticksmodulsfilen=”%s”"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Läste in insticksmodulen namn=”%s”, version=”%s”"
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath får inte vara tom"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Kan inte läsa katalogen för insticksmoduler ”%s”: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Kan inte läsa in insticksmodulen ”%s”: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Kaan inte skapa den temporära förrådskatalogen ”%s”: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Att använda operatorn ”==” i reldeps kan resultera i ett odefinierat "
+"beteende. Det undanbedes och stödet kommer tas bort i framtida versioner. "
+"Använd operatorn ”=” istället."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Förrådet %s har ingen spegel eller bas-url satt."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "Förrådet ”%s” har en typ som inte stödjs: ”type=%s”, hoppar över."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "förrådet ”%s”: ”basecachedir” är inte satt"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Maximal hämtningshastighet är mindre än minimum. Ändra konfigurationen av "
+"minrate eller throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "förrådet ”%s”: ”proxy_username” är satt men inte ”proxy_password”"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "”proxy_username” är satt men inte ”proxy_password”"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Kan inte hitta en giltig bas-url för förrådet: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Misslyckades att hämta GPG-nyckel för förrådet ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "förrådet %s: 0x%s är redan importerad"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Misslyckades med att skapa katalogen ”%s”: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "Paketkatalog %s: importerade nyckeln 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "återupplivar: förrådet ”%s” överhoppat, ingen metalink."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "återupplivar: förrådet ”%s” överhoppat, ingen användbar hash."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "återupplivar: misslyckades med ”%s”, %s-summor stämmer inte."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"återupplivar: ”%s” kan återupplivas – metalänkens kontrollsummor stämmer."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "återupplivar: ”%s” kan återupplivas – repomd stämmer."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "återupplivar: misslyckades med ”%s”, repomd stämmer inte."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Kan inte skapa målkatalogen för förrådet ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Kan inte skapa katalogen ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Kan inte byta namn på katalogen ”%s” till ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "förråd: använder cache för: %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Enbart-cache aktiverat men ingen cache för ”%s”"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "förråd: hämtar från fjärrförråd: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Misslyckades att hämta metadata för förrådet ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): Beräkningen av SHA256 misslyckades"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Det går inte att skapa ett persistdir ”%s”: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume kan inte användas samtidigt med parametern byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Initiering av PackageTarget misslyckades: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Kan inte öppna %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Logghanterare med id %ld finns inte"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Pågår"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Pågår inte"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Ingen transaktion pågår"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Försök att infoga transaktionsobjekt i en avslutad transaktion"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Försök att uppdatera transaktionsobjekt i en avslutad transaktion"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+"Databasen är trasig: det finns ingen rad ”version” i tabellen ”config”"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformerare: kan inte öppna historisk varaktig katalog"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Kan inte hitta en historiedatabas"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Transaktionen har redan påbörjats!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Transaktionsobjektets tillstånd inte satt: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Kan inte lägga till konsolutdata till en osparad transaktion"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "kan inte lista nycklar: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "misslyckades att lägga till lösning"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() misslyckades att skriva data: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() misslyckades att läsa om en skriven lösningsfil"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) har misslyckats: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() har misslyckats."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Det gick inte att analysera artefakt för modulen NEVRA '%s'"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "misslyckades att beräkna RPMDB-kontrollsumma"
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:38+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Tamil\n"
+"Language: ta\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "செயலில் உள்ளது"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:46+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Telugu\n"
+"Language: te\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "పురోగతినందు వుంది"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2015-03-23 08:56+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
+"Language-Team: Thai\n"
+"Language: th\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"X-Generator: Zanata 4.6.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr ""
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr ""
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr ""
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr ""
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr ""
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr ""
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] ""
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr ""
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr ""
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "กำลังดำเนินการ"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr ""
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr ""
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr ""
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr ""
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr ""
--- /dev/null
+# Emin Tufan Çetin <etcetin@gmail.com>, 2016. #zanata
+# Oğuz Ersen <oguzersen@protonmail.com>, 2020, 2021, 2022.
+# Oğuz Ersen <oguz@ersen.moe>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2022-06-24 07:18+0000\n"
+"Last-Translator: Oğuz Ersen <oguz@ersen.moe>\n"
+"Language-Team: Turkish <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/tr/>\n"
+"Language: tr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n>1);\n"
+"X-Generator: Weblate 4.13\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "değer belirtilmedi"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "saniye değeri '%s' negatif olmamalı"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "'%s', bayta dönüştürülemedi"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "bilinmeyen birim '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "geçersiz değer"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "1 değerine izin verilmiyor"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "negatif değere izin verilmiyor"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "yüzde değeri '%s' aralık dışında"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Yapılandırma: \"%s\" kimliğine sahip bir OptionBinding yok"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Yapılandırma: \"%s\" kimliğine sahip bir OptionBinding zaten var"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "geçersiz boolean değeri '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' izin verilen bir değer değil"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "verilen [%d] değeri, izin verilen [%d] değerinden az olmalıdır."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "verilen [%d] değeri, izin verilen [%d] değerinden büyük olmalıdır."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "verilen '%s' yolu mutlak değil."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "verilen '%s' yolu yok."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "'%s', saniyeye dönüştürülemedi"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): Değer ayarlanmadı"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Aynı anda '%s' modülünden daha fazla akış etkinleştirilemiyor"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"'%1$s' modülünün '%2$s' akışı etkinleştirilemiyor: Modülün durumu zaten "
+"değiştirildi"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Öntanımlı değerlerle modüler bağımlılık sorunu: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "En son modüllerle modüler bağımlılık sorunu: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Modüler bağımlılık sorunu: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "'%s' argümanı çözümlenemedi"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Yalnızca modül adı gereklidir. Argümandaki gereksiz bilgiler yok sayılıyor: "
+"'%s'"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "'%s' modülü sıfırlanamıyor: Modülün durumu zaten değiştirildi"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+"'%s' modülü devre dışı bırakılamıyor: Modülün durumu zaten değiştirildi"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Modüler veri yok"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Argümandaki gereksiz bilgiler yok sayılıyor: '%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"'%1$s' modülünün '%2$s' akışı için bağımlılık ağacı etkinleştirilirken sorun"
+" oluştu: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Modül etkinleştirme isteği için sorunlar ortaya çıktı:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "'%s' modül belirtimi için etkin modül paketi bulunamadı"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Fail-Safe deposundan '%s' modülü kurulamıyor"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "'%s' ile eşleşen profil bulunamadı"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "'%s' paketiyle (%s modül belirtimi için) eşleşme yok"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+"'%1$s' modülünün '%2$s' akışı için kurulum sırasında sorun oluştu: %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Modül kurma isteği için sorunlar ortaya çıktı:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Modül sıfırlama isteği için sorunlar ortaya çıktı:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Modül devre dışı bırakma isteği için sorunlar ortaya çıktı:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"İşlem, '%s' modülünün '%s' akışının '%s' akışına değiştirilmesine neden olur"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Bir modülün etkin akışlarını değiştirmek mümkün değildir.\n"
+"Kurulu tüm içeriği modülden kaldırmanız ve 'microdnf module reset <modül_adı>' komutunu kullanarak modülü sıfırlamanız tavsiye edilir. Modülü sıfırladıktan sonra diğer akışı kurabilirsiniz."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "İşlemin bağımlılıkları çözümlenemedi; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "%i sorun tespit edildi:\n"
+msgstr[1] "%i sorun tespit edildi:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " %1$i. sorun: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Sorun: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"'%s' modüler paketi için kullanılabilir modüler üst veri yok, sisteme "
+"kurulamıyor"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "%s için imza doğrulanamıyor"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "açılamadı (genel hata): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "%s için anahtar doğrulanamadı"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "%s için genel anahtar kullanılamıyor"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "%s için imza bulunamadı"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "install (kurulum) ögesi eklenemedi: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "İşlem çalıştırılırken hata oluştu: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "İşlem çalıştırılırken hata oluştu ve herhangi bir sorun bildirilmedi!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Ölümcül hata, veri tabanı kurtarma işlemini çalıştırın"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "%s paketi bulunamadı"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "erase (silme) ögesi eklenemedi: %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() başarısız oldu."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "%s (%d) uzantı önbelleği yüklenemedi: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "%2$s için %1$s dizgesi yok"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "açılamadı: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "geçici dosya oluşturulamıyor: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "geçici dosya açılamadı: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Birincil önbellek %s yazılırken repowriter yazma işlemi başarısız oldu: %i, "
+"hata: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Geçici dosya %s kapatılamadı: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Yeni yazılan birincil önbellek kullanılamadı: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Yeni yazılan birincil önbellek kullanılamadı: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "%s geçici dosyası oluşturulamıyor"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Uzantı önbelleği %s (%d) yazılırken repowriter yazma işlemi başarısız oldu: "
+"%i, hata: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr "Uzantı önbelleği (%d) yazılırken geçici dosya kapatılamıyor: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Yeni yazılan uzantı önbelleği kullanılamadı: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Yeni yazılan uzantı önbelleği kullanılamadı: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "boş depo md dosyası"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "%1$s dosyası okunamıyor: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Depo yüklenirken %s kullanılamadı: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "MD_TYPE_PRIMARY yüklenemedi."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Depo birincil verileri açılamadı: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "repomd yüklenemedi: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Birincil yüklenemedi: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "mimari otomatik olarak algılanamadı"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "%s önbellek dizini oluşturulamadı"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "RPMDB yüklenemedi"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Modül öntanımlı değerleri bulunamadı: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "yüzde 100 değil: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "adım sayısı ayarlanamadı: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "kullanıcı işlemi tarafından iptal edildi"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr ""
+"ayarlanmış bir boyutu olmayan %1$p durumu için 'tamamlandı' (done) çağrıldı "
+"[%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "zaten %%100 durumunda [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "%s paketi sağlanmaya çalışılırken kaynaklar ayarlanmadı"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "%2$s deposu bulunamadığı için %1$s sağlanamadı (%3$i depo yüklendi)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Güvenilmeyenler denetlenemedi: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "%s için indirilen dosya bulunamadı"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"%1$s paketi doğrulanamıyor ve %2$s deposu için GPG denetimi etkin: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "CacheDir değeri alınamadı"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "%s için dosya sistemindeki boş alan boyutu alınamadı: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "%s için dosya sistemindeki boş alan boyutu alınamadı"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "%1$s dizininde yeterli boş alan yok: %2$s gerekli, %3$s var"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "kök dizin ayarlanamadı"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "İşlem testi çalıştırılırken %i hatası"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "rpm veri tabanını açarken hata %i"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+"rpmdbCookie() işlevi rpm veri tabanının tanımlama çerezini döndürmedi."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "İşlem çalıştırılırken %i hatası"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "İşlem yazma aşamasına geçmedi, ancak hata döndürmedi (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "%1$s dizini açılamıyor: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "%s kaldırılamadı"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Yanlış oluşturulmuş Selector (seçici), filtrede birden fazla eşleşen nesne "
+"var"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"İşlem için yanlış oluşturulmuş Selector (seçici) kullanıldı, yanlış "
+"karşılaştırma türü"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "bir distupgrade deposuna ait değil"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "daha düşük bir mimariye sahip"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "kurulu paketle ilgili sorun "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "çakışan istekler"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "desteklenmeyen istek"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "hiçbir şey isteneni sağlamıyor "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "%s diye bir paket yok"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " sistem tarafından sağlanmaktadır"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "bazı bağımlılık sorunları"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "paket için en iyi güncelleme adayı kurulamıyor "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "görev için en iyi aday kurulamıyor"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "%s paketi modüler filtreleme ile filtrelendi"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "%s paketi uyumlu bir mimariye sahip değil"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "%s paketi kurulabilir değil"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "%s paketi hariç tutma filtresi ile filtrelendi"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "hiçbir şey %s'i (%s tarafından ihtiyaç duyulan) sağlamıyor"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "%s ve %s birlikte kurulamıyor"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "%s paketi %s ile (%s tarafından sağlanan) çakışıyor"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s paketi, %s'i (%s tarafından sağlanan) kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr ""
+"kurulu %s paketi, %s'i (%s tarafından sağlanan) kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"%s paketi, %s'i (%s tarafından sağlanan) dolaylı olarak kullanım dışı "
+"bırakıyor"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s paketi %s gerektiriyor, ancak sağlayanların hiçbiri kurulamıyor"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "%s paketi (kendisi tarafından sağlanan) %s ile çakışıyor"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "%s ve %s paketleri, %s'i kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "bir distupgrade deposuna ait değil"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "daha düşük bir mimariye sahip"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "kurulu modülle ilgili sorun "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "%s diye bir modül yok"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "modül için en iyi güncelleme adayı kurulamıyor "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "%s modülü devre dışı"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "%s modülü uyumlu bir mimariye sahip değil"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "%s modülü kurulabilir değil"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "hiçbir şey %s'i (%s modülü tarafından ihtiyaç duyulan) sağlamıyor"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "%s ve %s modülleri birlikte kurulamıyor"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "%s modülü %s ile (%s tarafından sağlanan) çakışıyor"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s modülü, %s'i (%s tarafından sağlanan) kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr ""
+"kurulu %s modülü, %s'i (%s tarafından sağlanan) kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"%s modülü, %s'i (%s tarafından sağlanan) dolaylı olarak kullanım dışı "
+"bırakıyor"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s modülü %s gerektiriyor, ancak sağlayanların hiçbiri kurulamıyor"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "%s modülü (kendisi tarafından sağlanan) %s ile çakışıyor"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "%s ve %s modülleri, %s'i kullanım dışı bırakıyor"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "çözücü ayarlanmadı"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "%s mutlak hale getirilemedi"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "hata ayıklama verileri %1$s dosyasına yazılamadı: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "hedefte 'solv' yok"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "çözüm yok, korumalı paket kaldırılamıyor"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "olası bir çözüm yok"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Sorun: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Sorun %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "İşlem, aşağıdaki korumalı paketlerin kaldırılmasına neden olur: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Libsolv solv_toolversion %zu uzunluğunda en fazla %zu bekleniyor"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "%1$s, %2$s olarak yeniden adlandırılamadı: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "%1$s için izinler ayarlanamadı: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "%1$s dizini oluşturulamıyor: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "%1$s yolu için dosya bilgileri alınamıyor: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Geçersiz platform modülü biçimi: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr ""
+"Kullanılabilir paketler tarafından birden çok modül platformu sağlanıyor\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Kurulu paketler tarafından birden çok modül platformu sağlanıyor\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "%s yolunda platform modülü algılanamadı: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "%s yolunda PLATFORM_ID eksik"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Geçerli bir platform kimliği algılanmadı"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "'%s' modülü için birden çok akış etkinleştirilemiyor"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Öntanımlı değerler '%s' deposu ile çakışıyor: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Modül profilleri kuruluyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Modül profilleri devre dışı bırakılıyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Modül akışları etkinleştiriliyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Modül akışları değiştiriliyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Modüller devre dışı bırakılıyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Modüller sıfırlanıyor:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "'%s' dosyasında modüler Fail-Safe verileri yüklenemedi"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "'%s:%s' modülü için modüler Fail-Safe verileri yüklenemedi"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "Modüler Fail Safe verileri için \"%s\" dizini oluşturulamadı: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "'%s' dosyasına bir modüler Fail Safe verisi kaydedilemedi"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "'%s' dosyasından bir modüler Fail Safe verisi kaldırılamadı"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"'%s:%s' için modüler kullanım dışı bırakılanlar uygulanamadı çünkü hedef "
+"modül '%s' devre dışı"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Dizgeden güncellenemedi: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Çözümlenemedi: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Modüler öntanımlı değerler çözümlenirken hatalar oluştu: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Öntanımlı değerler yükseltilemedi: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Akışlar yükseltilemedi: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"%s: %s ile eşleşen akış olmadığı için modül kullanım dışı bırakılanları "
+"alınamıyor"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "\"%s\" paylaşımlı kütüphanesi yüklenemiyor: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "\"%s\" sembolünün adresi alınamıyor: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Eklenti dosyası=\"%s\" yükleniyor"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Eklenti yüklendi, isim=\"%s\", sürüm=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dizin yolu (dirPath) boş olamaz"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Eklenti dizini \"%s\" okunamıyor: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "\"%s\" eklentisi yüklenemiyor: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Depo geçici dizini \"%s\" oluşturulamıyor: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Reldeps içinde '==' işleminin kullanılması tanımsız bir davranışa neden "
+"olabilir. Bu kullanımdan kaldırılmıştır ve gelecek sürümlerde destek "
+"kaldırılacaktır. Bunun yerine '=' işlemini kullanın."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "%s deposunun ayarlanmış bir yansısı veya temel url'si yok."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "'%s' deposunun desteklenmeyen bir türü var: 'type=%s', atlanıyor."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "depo '%s': 'basecachedir' ayarlanmadı"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Azami indirme hızı asgariden düşük. Lütfen 'minrate' veya 'throttle' "
+"yapılandırmasını değiştirin"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"depo '%s': 'proxy_username' ayarlandı ama 'proxy_password' ayarlanmadı"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' ayarlandı ama 'proxy_password' ayarlanmadı"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "%s deposu için geçerli bir temel url bulunamıyor"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "'%s' deposu için GPG anahtarı alınamadı: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "depo %s: 0x%s zaten içe aktarıldı"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "\"%s\" dizini oluşturulamadı: %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "depo %s: 0x%s anahtarı içe aktarıldı."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "yeniden etkinleştirme: '%s' deposu atlandı, üst bağlantı yok."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr ""
+"yeniden etkinleştirme: '%s' deposu atlandı, kullanılabilir sağlama kodu yok."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "yeniden etkinleştirme: '%s' için başarısız, %s toplamı eşleşmiyor."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"yeniden etkinleştirme: '%s' yeniden etkinleştirilebilir - üst bağlantı "
+"sağlama toplamları eşleşiyor."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr ""
+"yeniden etkinleştirme: '%s' yeniden etkinleştirilebilir - repomd eşleşiyor."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "yeniden etkinleştirme: '%s' için başarısız, repomd eşleşmiyor."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Depo hedef dizini \"%s\" oluşturulamıyor: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "\"%s\" dizini oluşturulamıyor: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "\"%s\" dizini \"%s\" olarak yeniden adlandırılamıyor: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo: %s için önbellek kullanılıyor"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Yalnızca-önbellek modu etkin ancak '%s' için önbellek yok"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo: %s uzak deposundan indiriliyor"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "'%s' deposu için üst veriler indirilemedi: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): SHA256 hesaplaması başarısız oldu"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "\"%s\" kalıcı dizini oluşturulamıyor: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "'resume', 'byterangestart' parametresiyle aynı anda kullanılamaz"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget başlatılamadı: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "%s açılamıyor: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "%ld kimliğine sahip bir günlük kaydı işleyici yok"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Devam ediyor"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Devam etmiyor"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Devam eden işlem yok"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Tamamlanan işleme bir işlem ögesi ekleme girişimi"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Tamamlanan işlemdeki işlem ögesini güncelleme girişimi"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Bozuk Veri Tabanı: 'config' tablosunda 'version' satırı yok"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer: kalıcı geçmiş dizini açılamıyor"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Bir geçmiş veri tabanı bulunamadı"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "İşlem zaten başladı!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem durumu ayarlanmadı: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Kaydedilmemiş işleme konsol çıktısı eklenemiyor"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "anahtarlar listelenemiyor: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "'solv' eklenemedi"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() veri yazamadı: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() yazılı 'solv' dosyasını yeniden yükleyemedi"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) başarısız oldu: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() başarısız oldu."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Modül yapısı NEVRA değeri '%s' ayrıştırılamadı"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Depo için hatalı kimlik: %s, bayt = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "RPMDB sağlama toplamı hesaplanamadı"
--- /dev/null
+# Yuri Chornoivan <yurchor@ukr.net>, 2016. #zanata, 2020, 2021, 2022, 2023.
+# Yuri Chornoivan <yurchor@ukr.net>, 2017. #zanata, 2020, 2021, 2022, 2023.
+# Yuri Chornoivan <yurchor@ukr.net>, 2018. #zanata, 2020, 2021, 2022, 2023.
+# Yuri Chornoivan <yurchor@ukr.net>, 2019. #zanata, 2020, 2021, 2022, 2023.
+# Yuri Chornoivan <yurchor@ukr.net>, 2020. #zanata, 2021, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-04-01 09:19+0000\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
+"Language-Team: Ukrainian <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/uk/>\n"
+"Language: uk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "значення не задано"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "значення для секунд, «%s», має бути невід’ємним"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "не вдалося перетворити «%s» на байти"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "невідома одиниця, «%s»"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "некоректне значення"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "значення 1 не є дозволеним"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "не можна використовувати від'ємні значення"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "значення відсотків, «%s», поза припустимим діапазоном"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "Налаштування: OptionBinding з ідентифікатором «%s» не існує"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "Налаштування: OptionBinding з ідентифікатором «%s» вже існує"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "некоректне булеве значення «%s»"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "«%s» не є дозволеним значенням"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "задане значення [%d] має бути меншим за дозволене значення [%d]."
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "задане значення [%d] має бути більшим за дозволене значення [%d]."
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "вказаний шлях, «%s», не є абсолютним."
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "вказаного шляху, «%s», не існує."
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "не вдалося перетворити «%s» на секунди"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): значення не встановлено"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "Не вдалося увімкнути додаткові потоки з модуля «%s» одночасно"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+"Не вдалося увімкнути потік модуля «%1$s» «%2$s»: стан модуля вже змінено"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "Проблема із залежностями модулів у Defaults: %s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "Проблема із залежностями модулів для найсвіжіших модулів: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "Проблема із залежностями модулів: %s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "Не вдалося обробити аргумент «%s»"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+"Потрібна лише назва модуля. Непотрібні дані у аргументі проігноровано: «%s»"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "Не вдалося скинути модуль «%s»: стан модуля вже змінено"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "Не вдалося вимкнути модуль «%s»: стан модуля вже змінено"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "Немає доступних даних модуля"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "Ігноруємо непотрібні дані в аргументі: «%s»"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+"Проблема під час вмикання ієрархії залежностей для модуля «%1$s», потік "
+"«%2$s»: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "Виникли проблеми із запитом щодо вмикання модуля:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "Для специфікації модуля «%s» не знайдено активних пакунків модулів"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "Не вдалося встановити модуль «%s» з безпечного сховища"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "Не знайдено профілю, який відповідає «%s»"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "Немає відповідників для пакунка «%s» для специфікації модуля %s"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "Проблема під час встановлення модуля «%1$s», потік «%2$s»: %3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "Виникли проблеми із запитом щодо встановлення модуля:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "Виникли проблеми із запитом щодо скидання модуля:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "Виникли проблеми із запитом щодо вимикання модуля:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+"Результатом дії має бути перемикання потоку модуля «%s» «%s» на потік «%s»"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"Не можна перемикати увімкнені потоки модуля.\n"
+"Рекомендуємо вилучити усі встановлені дані з модуля і відновити початковий стан модуля за допомогою команди «microdnf module reset <назва_модуля>». Після відновлення початкового стану модуля ви зможете встановити інший потік."
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "Не вдалося розв'язати залежності операції; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "Виявлено %i проблему:\n"
+msgstr[1] "Виявлено %i проблеми:\n"
+msgstr[2] "Виявлено %i проблем:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " Проблема %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " Проблема: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr ""
+"Немає доступних модульних метаданих для модульного пакунка «%s»; "
+"встановлення у системі неможливе"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "не перевірено підпис для %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "не вдалося відкрити (загальна помилка): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "не вдалося перевірити ключ для %s"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "відкритий ключ для %s недоступний"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "не знайдено підпису для %s"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "не вдалося додати елемент встановлення: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "Помилка під час виконання операції: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr ""
+"Помилка під час виконання операції, а звітів щодо проблем не надходило!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "Критична помилка, виконуємо відновлення бази даних"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "не вдалося знайти пакунок %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "не вдалося додати елемент вилучення %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "помилка repo_add_solv()."
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "Помилка під час завантаження кешу розширень %s (%d): "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "немає рядка %1$s для %2$s"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "не вдалося відкрити: %s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "не вдалося створити тимчасовий файл: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "не вдалося відкрити тимчасовий файл: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+"Помилка запису основного кешу %s засобом запису сховища: %i, повідомлення "
+"про помилку: %s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "Не вдалося закрити тимчасовий файл: %s: %s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "Не вдалося скористатися наново записаним основним кешем: %s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "Не вдалося скористатися наново записаним основним кешем: %s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "не вдалося створити тимчасовий файл %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+"Помилка запису кешу розширень %s (%d): помилка запису засобу запису сховища:"
+" %i, повідомлення про помилку: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+"Під час запису кешу розширень (%d): не вдалося закрити тимчасовий файл: %s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "Не вдалося скористатися наново записаним кешем розширень: %s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "Не вдалося скористатися наново записаним кешем розширень: %s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "порожній файл md сховища"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "не вдалося прочитати файл %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "Під час завантаження сховища не вдалося скористатися %s: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "не вдалося завантажити MD_TYPE_PRIMARY."
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "Не вдалося відкрити основні дані сховища: %s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "Не вдалося завантажити repomd: %s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "Не вдалося завантажити основний: %s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "не вдалося автоматично визначити архітектуру"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "не вдалося створити каталог кешу %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "не вдалося завантажити RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "Не знайдено типових налаштувань модуля: %s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "частка не дорівнює 100 процентам: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "не вдалося встановити числові кроки: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "скасовано дією користувача"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "виконано при стані %1$p, для якого не встановлено розміру! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "вже на рівні 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "Джерела не встановлено під час спроби забезпечити пакунок %s"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr ""
+"Не вдалося забезпечити %1$s, оскільки сховище %2$s не знайдено (завантажено "
+"%3$i сховищ)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "Не вдалося перевірити недовірене: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "Отриманий файл для %s не знайдено"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr ""
+"не вдалося перевірити пакунок %1$s, а сховище %2$s є сховищем із увімкненим "
+"GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "Не вдалося отримати значення для CacheDir"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "Не вдалося отримати дані щодо вільного місця у файловій системі %s: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "Не вдалося отримати дані щодо вільного місця у файловій системі %s"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "Недостатньо вільного місця у %1$s: потрібно %2$s, доступно %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "не вдалося встановити root"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "Помилка %i під час перевірки операції"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "Помилка %i під час відкриття бази даних rpm"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "Функцією rpmdbCookie() не повернуто куки бази даних rpm."
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "Помилка %i під час виконання операції"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr ""
+"Операція не перейшла у фазу запису, але повідомлення про помилку не "
+"повернуто (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "не вдалося відкрити каталог %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "не вдалося вилучити %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr ""
+"Помилкове формування Selector, наявність декількох відповідних об'єктів у "
+"фільтрі"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr ""
+"Для дії використано помилкове формування Selector, помилковий тип порівняння"
+
+#: libdnf/goal/Goal.cpp:90
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s з %s не належить до сховища оновлення дистрибутива"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s з %s належить до гіршої архітектури"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "проблема зі встановленим пакунком "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "конфлікт запитів"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "непідтримуваний запит"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "нічого з пакунків не містить потрібного "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "пакунка %s не існує"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " надається системою"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "якась проблема із залежностями"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "не вдалося встановити найкращий варіант оновлення для пакунка "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "не вдалося встановити найкращий варіант для завдання"
+
+#: libdnf/goal/Goal.cpp:101
+#, c-format
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "пакунок %s з %s відфільтровано модульним фільтруванням"
+
+#: libdnf/goal/Goal.cpp:102
+#, c-format
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "немає пакунка %s з %s із сумісною архітектурою"
+
+#: libdnf/goal/Goal.cpp:103
+#, c-format
+msgid "package %s from %s is not installable"
+msgstr "пакунок %s з %s є непридатним до встановлення"
+
+#: libdnf/goal/Goal.cpp:104
+#, c-format
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "пакунок %s з %s відфільтровано фільтруванням виключення"
+
+#: libdnf/goal/Goal.cpp:105
+#, c-format
+msgid "nothing provides %s needed by %s from %s"
+msgstr "немає пакунків із %s, потрібним для %s з %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, c-format
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "неможливо встановити одразу %s з %s і %s з %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, c-format
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "пакунок %s з %s конфліктує з %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:108
+#, c-format
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "пакунок %s з %s робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, c-format
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "встановлений пакунок %s робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, c-format
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"пакунок %s з %s неявним чином робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, c-format
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"пакунок %s з %s потребує %s, але жоден з пакунків, які його надають, не може"
+" бути встановлено"
+
+#: libdnf/goal/Goal.cpp:112
+#, c-format
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "пакунок %s з %s конфліктує з %s, що надається самим цим пакунком"
+
+#: libdnf/goal/Goal.cpp:113
+#, c-format
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "обидва пакунки, %s з %s і %s з %s, роблять застарілим пакунок %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, c-format
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "%s з %s не належить до сховища оновлення дистрибутива"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr "%s з %s належить до гіршої архітектури"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "проблема зі встановленим модулем "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "модуля %s не існує"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "не вдалося встановити найкращий варіант оновлення для модуля "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, c-format
+msgid "module %s from %s is disabled"
+msgstr "модуль %s з %s вимкнено"
+
+#: libdnf/goal/Goal.cpp:129
+#, c-format
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "у модуля %s з %s немає сумісної архітектури"
+
+#: libdnf/goal/Goal.cpp:130
+#, c-format
+msgid "module %s from %s is not installable"
+msgstr "модуль %s з %s є непридатним до встановлення"
+
+#: libdnf/goal/Goal.cpp:132
+#, c-format
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "жоден пакунок не надає %s, який потрібен для модуля %s з %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, c-format
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "одночасне встановлення модулів %s з %s і %s з %s неможливе"
+
+#: libdnf/goal/Goal.cpp:134
+#, c-format
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "модуль %s з %s конфліктує з %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:135
+#, c-format
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "модуль %s з %s робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, c-format
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "встановлений модуль %s робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, c-format
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr ""
+"модуль %s з %s неявним чином робить застарілим %s, що надається %s з %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, c-format
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr ""
+"модуль %s з %s потребує %s, але жоден з пакунків, які його надають, не може "
+"бути встановлено"
+
+#: libdnf/goal/Goal.cpp:139
+#, c-format
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "модуль %s з %s конфліктує з %s, що надається самим цим пакунком"
+
+#: libdnf/goal/Goal.cpp:140
+#, c-format
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "обидва модулі, %s з %s і %s з %s, роблять застарілим %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "не встановлено розв'язувача"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "не вдалося зробити %s абсолютним"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "не вдалося записати діагностичні дані до %1$s: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "немає solv у цілі"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "немає розв'язку, неможливо вилучити захищений пакунок"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "розв'язання неможливе"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "Проблема: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "Проблема %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "Дія призведе до вилучення таких захищених пакунків: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Версія solv_tool libsolve: %zu але нам потрібна максимально така: %zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "Не вдалося перейменувати %1$s на %2$s: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "Не вдалося встановити права доступу %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "Не вдалося створити каталог %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "не вдалося отримати статистичні дані для шляху %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Некоректний формат модуля платформи: %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "Доступними пакунками надано декілька платформ модулів\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "Встановленими пакунками надано декілька платформ модулів\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "Не вдалося визначити модуль платформи у %s: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "Пропущено PLATFORM_ID у %s"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "Не виявлено коректного ідентифікатора платформи"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "Не вдалося увімкнути декілька потоків для модуля «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "Конфлікт типових параметрів із сховищем «%s»: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "Встановлюємо профілі модуля:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "Вимикаємо профілі модуля:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "Вмикаємо потоки модуля:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "Перемикаємо потоки модуля:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "Вимикаємо модулі:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "Відновлюємо початковий стан модулів:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "Не вдалося завантажити модульні дані безпечного встановлення у «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr ""
+"Не вдалося завантажити модульні дані безпечного встановлення для модуля "
+"«%s:%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr ""
+"Не вдалося створити каталог «%s» для модульних даних для безпечного "
+"встановлення: %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "Не вдалося зберегти модульні дані для безпечного встановлення до «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "Не вдалося вилучити модульні дані для безпечного встановлення з «%s»"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+"Не вдалося застосувати дані щодо застарівання за модулями до «%s:%s», "
+"оскільки модуль призначення «%s» вимкнено"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "Не вдалося оновити з рядка: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "Не вдалося визначити: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "Під час розв'язання типових залежностей модуля сталися помилки: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "Не вдалося оновити типові значення: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "Не вдалося оновити потоки: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+"Не вдалося отримати застарілі пакунки для модуля, оскільки немає потоку, що "
+"відповідає запису %s: %s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "Не вдалося завантажити бібліотеку спільного використання «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "Не вдалося отримати адресу символу «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "Завантажуємо додаток, файл=«%s»"
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "Завантажено додаток: назва=«%s», версія=«%s»"
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr ""
+"Шлях до каталогу (dirPath) у Plugins::loadPlugins() не може бути порожнім"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "Не вдалося виконати читання з каталогу додатка «%s»: %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "Не вдалося завантажити додаток «%s»: %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "Не вдалося створити тимчасовий каталог сховища «%s»: %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"Використання оператора «==» у reldeps може призвести до невизначеної "
+"поведінки. Таке використання вважається застарілим — його підтримку буде "
+"вилучено у майбутніх версіях. Скористайтеся натомість оператором «=»."
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "Для сховища %s не встановлено дзеркала або базової адреси."
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr ""
+"Сховище «%s» належить до непідтримуваного типу: «type=%s», пропускаємо."
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "сховище «%s»: не встановлено «basecachedir»"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr ""
+"Максимальна швидкість отримання даних є меншою за мінімальну. Будь ласка, "
+"змініть значення для minrate або throttle"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+"сховище «%s»: встановлено «proxy_username», але не встановлено "
+"«proxy_password»"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "встановлено «proxy_username», але не встановлено «proxy_password»"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "Не вдалося знайти коректну базову адресу для сховища: %s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "Не вдалося отримати ключ GPG для сховища «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "сховище %s: 0x%s вже імпортовано"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "Не вдалося створити каталог «%s»: %d — %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "сховище %s: імпортовано ключ 0x%s."
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "відновлюємо: сховище «%s» пропущено, немає метапосилання."
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "відновлюємо: сховище «%s» пропущено, немає придатного хешу."
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "відновлюємо: помилка обробки «%s», невідповідна контрольна сума %s."
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr ""
+"відновлюємо: «%s» можна відновити — контрольні суми метапосилань збігаються."
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "відновлюємо: «%s» можна відновити — значення repomd збігаються."
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "відновлюємо: помилка обробки «%s», невідповідність repomd."
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "Не вдалося створити каталог призначення сховища «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "Не вдалося створити каталог «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "Не вдалося перейменувати каталог «%s» на «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "сховище: використовуємо кеш для %s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "Увімкнено отримання даних лише з кешу, але немає кешу для «%s»"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "сховище: отримуємо з віддаленого сховища: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "Не вдалося отримати метадані для сховища «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): помилка під час обчислення SHA256"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "Не вдалося створити сталий каталог «%s»: %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume не можна використовувати одночасно з параметром byterangestart"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "Помилка ініціалізації PackageTarget: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "Не вдалося відкрити %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "Обробника журналу із ідентифікатором %ld не існує"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "Триває обробка"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "Не виконується"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "Немає операції, яка виконується"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "Спроба вставити пункт операції до завершеної операції"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "Спроба оновити запис операції у завершеній операції"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "Пошкоджено базу даних: немає рядка «version» у таблиці «config»"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Трансформер: не вдалося відкрити сталий каталог журналу"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "Не вдалося знайти базу даних журналу"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "Операцію вже розпочато!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "Стан TransactionItem не встановлено: %s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "Неможливо додати виведення до консолі до незбереженої операції"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "не вдалося побудувати список ключів: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "не вдалося додати solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() не вдалося записати дані: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() не вдалося перезавантажити записаний файл solv"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "помилка write_ext(%1$d): %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "помилка repo_add_repomdxml/rpmmd()."
+
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "Не вдалося обробити ідентифікатор модуля NEVRA «%s»"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "Помилковий ідентифікатор сховища: %s, байт = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "не вдалося обчислити контрольну суму RPMDB"
--- /dev/null
+# Charles Lee <lchopn@gmail.com>, 2017. #zanata, 2020, 2021.
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata, 2021.
+# Qiyu Yan <yanqiyu01@gmail.com>, 2021.
+# Sundeep Anand <suanand@redhat.com>, 2021, 2022.
+# Transtats <suanand@redhat.com>, 2022, 2023.
+# Yang Yulin <yylteam@icloud.com>, 2022.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2023-03-07 14:20+0000\n"
+"Last-Translator: Transtats <suanand@redhat.com>\n"
+"Language-Team: Chinese (Simplified) <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/zh_CN/>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.15.2\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "未指定值"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "第二个值“%s”必须不能为负"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "无法把 '%s' 转换为字节"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "未知单元 '%s'"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "无效值"
+
+#: libdnf/conf/ConfigMain.cpp:207
+msgid "value 1 is not allowed"
+msgstr "1 不是一个被允许的值"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr "负数值不被允许"
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "百分数 '%s' 超出范围"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "配置:ID 为 \"%s\" 的 OptionBinding 不存在"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "配置:ID 为 \"%s\" 的 OptionBinding 已存在"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "无效的布尔值 '%s'"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "'%s' 不是一个允许的值"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "给定的值 [%d] 应小于允许的值 [%d]。"
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "给定的值 [%d] 应大于允许的值 [%d]。"
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "给定的路径 “%s” 不是绝对路径。"
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "给定的路径 “%s” 不存在。"
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "无法把 '%s' 转换为秒"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): 值没有设置"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, c-format
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "无法同时从模块 '%s' 中启用更多流"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr "无法启用模块 '%1$s' 流 '%2$s':已经修改的模块状态"
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr "默认设置的模块依赖性问题:%s"
+
+#: libdnf/dnf-context.cpp:3303
+#, c-format
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "最新模块的模块化依赖关系问题: %s"
+
+#: libdnf/dnf-context.cpp:3307
+#, c-format
+msgid "Modular dependency problem: %s"
+msgstr "模块依赖问题:%s"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, c-format
+msgid "Unable to resolve argument '%s'"
+msgstr "无法解析参数 '%s'"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr "只需要模块名。忽略参数 '%s' 中的无用信息"
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr "无法重置模块 '%s':已修改的模块状态"
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr "无法禁用模块 '%s':已经修改的模块状态"
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr "没有可用的模块数据"
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr "忽略参数中不需要的信息:'%s'"
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr "为模块 '%1$s' 流 '%2$s' 启用依赖树时出现问题: %3$s"
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr "模块启用请求出现问题:"
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr "未找到模块规范 '%s' 的活动模块包"
+
+#: libdnf/dnf-context.cpp:3560
+#, c-format
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "无法从故障保护存储库安装模块 '%s'"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr "未找到匹配 '%s' 的配置文件"
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr "没有匹配模块规范 %s 的包 '%s'"
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr "在安装模块 '%1$s' 流 '%2$s'时的问题:%3$s"
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr "模块安装请求出现问题:"
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr "模块重置请求出现问题:"
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr "模块禁用请求出现问题:"
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr "这个操作会把模块 '%s' 从流 '%s' 切换到流 '%s'"
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+"无法切换一个模块已启用的流。 \n"
+"推荐从模块中删除所有已安装的内容,使用 'microdnf module reset <module_name>' 命令重置模块。在重置模块后就可以安装其他流。"
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "无法 depsolve 事务; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "发现 %i 问题:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " 问题 %1$i: %2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " 问题: %s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr "模块软件包 '%s' 没有可用的模块元数据,它将不能被安装至此系统上"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "没有为 %s 验证签名"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "无法打开(一般错误): %s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "无法为 %s 验证密钥"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "没有 %s 的公钥"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "没有找到 %s 的签名"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "无法添加安装元素: %1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "错误运行事务: %s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "错误运行事务并且没有报告问题!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "严重错误,运行数据库恢复"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "无法找到软件包 %s"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "无法添加删除元素 %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() 已失败。"
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr "加载扩展缓存 %s (%d) 失败: "
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "没有 %2$s 的 %1$s 字符串"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "打开失败:%s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "不能创建临时文件: %s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "打开 tmp 文件失败: %s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr "写主缓存 %s 时 repowriter 写失败:%i 错误:%s"
+
+#: libdnf/dnf-sack.cpp:560
+#, c-format
+msgid "Failed closing tmp file %s: %s"
+msgstr "关闭临时文件 %s 失败:%s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr "使用新写的主缓存失败:%s: "
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr "使用新写的主缓存失败:%s"
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "不能创建临时文件 %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr "编写扩展缓存 %s (%d) 时: repowriter 写失败: %i,错误: %s"
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr "编写扩展缓存 (%d) 时:无法关闭临时文件:%s"
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr "使用新写的扩展缓存失败:%s (%d): "
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr "使用新写的扩展缓存失败:%s (%d)"
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null 存储库 md 文件"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "不能读文件 %1$s: %2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr "加载软件仓库时使用 %s 失败: "
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "加载 MD_TYPE_PRIMARY 失败。"
+
+#: libdnf/dnf-sack.cpp:784
+#, c-format
+msgid "Opening repository primary data has failed: %s"
+msgstr "打开仓库主数据失败:%s"
+
+#: libdnf/dnf-sack.cpp:795
+#, c-format
+msgid "Loading repomd has failed: %s"
+msgstr "加载 repomd 失败:%s"
+
+#: libdnf/dnf-sack.cpp:806
+#, c-format
+msgid "Loading primary has failed: %s"
+msgstr "加载主设备失败:%s"
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "自动检测架构失败"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "无法创建 cachedir %s"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "无法加载 RPMDB"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "没有找到模块默认设置:%s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "百分比不是 100: %i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "无法设置 number steps: %i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "由用户的操作取消"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "在一个没有设置大小的状态 %1$p 中做! [%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "已是 100%% 状态 [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "在尝试确保软件包 %s 时源没有设置"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "无法确保 %1$s,因为存储库 %2$s 没有找到 (%3$i 存储库已加载)"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "检查不被信任失败 : "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "没有找到下载的文件 %s"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "软件包 %1$s 不能被验证,存储库 %2$s 启用了 GPG: %3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "无法为 CacheDir 获得值"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "无法为 %s 获得文件系统可用空间的大小: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "无法为 %s 获得文件系统可用空间的大小"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "%1$s 没有足够的空闲空间: 需要 %2$s,可用 %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "设置 root 失败"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "运行事务测试时错误 %i"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr "打开 rpm 数据库时错误 %i"
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr "rpmdbCookie()函数没有返回 rpm 数据库的 cookie。"
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "运行事务时错误 %i"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "事务没有进入写阶段,但没有返回错误(%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "无法打开目录 %1$s: %2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "无法删除 %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "Ill-formed Selector,在过滤器中有多个匹配的对象"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "这个操作使用了 Ill-formed Selector,不正确的比较类型"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "不属于 distupgrade 仓库"
+
+#: libdnf/goal/Goal.cpp:91
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "有 inferior 架构"
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "安装的软件包的问题 "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "冲突的请求"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "不支持的请求"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "没有东西可以提供所请求的 "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "软件包 %s 不存在"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " 由系统提供"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "一些依赖问题"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "无法为软件包安装最佳更新候选 "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "无法为该任务安装最佳候选"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "软件包 %s 被模块过滤过滤掉"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "软件包 %s 没有兼容的架构"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "软件包 %s 不可安装"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "软件包 %s 被排除过滤过滤掉"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "没有提供 %s 所需要的 %s"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "无法同时安装 %s 和 %s"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "软件包 %s 与 %s(由 %s 提供)冲突"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "软件包 %s 淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "已安装的软件包 %s 淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "软件包 %s 隐式地淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "软件包 %s 需要 %s,但没有提供者可以被安装"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "软件包 %s 与自己提供的 %s 冲突"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "软件包 %s 和 %s 同时取代了 %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "不属于 distupgrade 仓库"
+
+#: libdnf/goal/Goal.cpp:118
+#, fuzzy, c-format
+#| msgid " has inferior architecture"
+msgid "%s from %s has inferior architecture"
+msgstr "有 inferior 架构"
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "已安装模块的问题 "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "模块 %s 不存在"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "无法为模块安装最佳更新候选 "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "模块 %s 被禁用"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "模块 %s 没有兼容的架构"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "模块 %s 不可安装"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "没有提供模块 %s 所需要的 %s"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "不能同时安装模块 %s 和 %s"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "模块 %s 与 %s 提供的 %s 冲突"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "模块 %s 淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "已安装的模块 %s 淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "模块 %s 隐式地淘汰了 %s 提供的 %s"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "模块 %s 需要 %s,但无法安装任何提供程序"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "模块 %s 与自己提供的 %s 冲突"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "模块 %s 和 %s 同时取代了 %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "无 solver 设置"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "无法使 %s 绝对"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "把 debugdata 写入到 %1$s 失败: %2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "在目标中没有 solv"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "没有解决方案,不能删除保护的软件包"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "没有可能的解决方案"
+
+#: libdnf/goal/Goal.cpp:1323
+msgid "Problem: "
+msgstr "问题: "
+
+#: libdnf/goal/Goal.cpp:1328
+#, c-format
+msgid "Problem %d: "
+msgstr "问题 %d: "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "这个操作将会导致删除以下受保护的软件包: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr "Libsolv 的 solv_toolversion 为: %zu,但我们预计最大为:%zu"
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "将 %1$s 重命名为 %2$s 失败: %3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "在 %1$s 中设置 perms 失败: %2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "无法创建目录 %1$s: %2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "无法 stat 路径 %1$s: %2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Platform 模块格式无效 : %s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "可用软件包提供了多个模块平台\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "已安装的软件包提供了多个模块平台\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "检测 %s 中的 Platform 模块失败: %s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "在 %s 中缺少 PLATFORM_ID"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "没有检测到有效的 Platform ID"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "无法为模块 '%s' 启用多个流"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "默认设置与存储库 '%s' 冲突 : %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr "安装模块配置档案:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr "禁用模块配置档案:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr "启用模块流:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr "切换模块流:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr "禁用模块:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr "重置模块:\n"
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "无法加载位于 '%s' 的模块 Fail-Safe 数据"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "无法为模块 '%s:%s' 加载模块 Fail-Safe 数据"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "无法为模块 Fail Safe 数据创建目录 \"%s\" : %s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "无法把模块 Fail Safe 数据保存到 '%s'"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "无法删除 '%s' 中的模块 Fail Safe 数据"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr "无法将模块化过时应用到 '%s:%s',因为目标模块 '%s' 被禁用"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "无法从字符串更新: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "无法解析: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "在解析模块默认值时出现了错误:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "无法升级默认值: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "升级流失败: %s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr "无法获取模块过时,因为没有流匹配 %s:%s"
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "无法加载共享库 \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "无法获取符号 \"%s\" 的地址: %s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "正在加载插件文件=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "已加载插件名=\"%s\", 版本=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath 不能为空"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "无法读取插件目录 \"%s\": %s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "无法加载插件 \"%s\": %s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "无法创建存储库临时目录 \"%s\": %s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+"在 reldeps 中使用 '==' 操作符可能导致一个未定义的行为。这个操作符已被废弃,并且在未来的版本中会取消对它的支持。请使用 '=' "
+"操作符代替。"
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "软件仓库 %s 没有设置镜像或者 baseurl。"
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "仓库 '%s' 有不被支持的类型: 'type=%s', 忽略。"
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr "存储库 '%s': 'basecachedir' 没有设置"
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr "最大下载速度低于最小值。请修改 minrate 或 throttle 的配置"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr "存储库 '%s': 'proxy_username' 已被设置,但没有设置 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr "'proxy_username' 已被设置,但没有设置 'proxy_password'"
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "无法为存储库找到一个有效的 baseurl:%s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "为仓库 '%s' 获取 GPG 密钥失败 : %s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "存储库 %s: 0x%s 已被导入"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, c-format
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "无法创建目录 \"%s\": %d - %s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "存储库 %s: 已导入密钥 0x%s。"
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "恢复中: 仓库 '%s' 已被跳过,无 metalink。"
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "恢复中: 仓库 '%s' 已被跳过,无可用 hash。"
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "恢复: '%s' 失败,不匹配的 %s sum。"
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr "恢复中: '%s' 可以被恢复 - metalink 校验和匹配。"
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "恢复: '%s' 可用被恢复 - repomd 匹配。"
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "恢复: '%s' 失败,不匹配的 repomd。"
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "无法创建仓库目标目录 \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "无法创建目录 \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "无法把目录 \"%s\" 重命名为 \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "存储库:使用缓存用于:%s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "仅启用缓存,但没有 '%s' 的缓存"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "存储库: 从远程下载: %s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "为仓库 '%s' 下载元数据失败 : %s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): 计算 SHA256 失败"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "无法创建 persistdir \"%s\": %s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume 不能和 the byterangestart 参数同时使用"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget 初始失败: %s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "无法打开 %s: %s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "id 为 %ld 的日志处理器不存在"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "进行中"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "没有在进行中"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "没有事务在进行中"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "试图向已完成的事务中插入事务项"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "试图在已完成的事务中更新事务"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "数据库损坏:表 'config' 中没有 'version' 行"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "转换程序: 无法打开历史持久目录"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "无法打开一个历史数据库"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "事务已开始!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "TransactionItem 状态没有设置:%s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "无法向未保存的事务中添加控制台输出"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "不能列出 key: %s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "添加 solv 失败"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() 写数据失败: %i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() 重新加载写的 solv 文件失败"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) 已失败: %2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() 已失败。"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "repo 的 id 无效: %s, byte = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "无法计算 RPMDB checksum"
--- /dev/null
+# Ludek Janda <ljanda@redhat.com>, 2018. #zanata
+# Peter Pan <pan93412@gmail.com>, 2018. #zanata
+# Cheng-Chia Tseng <pswo10680@gmail.com>, 2019. #zanata
+# Yi-Jyun Pan <pan93412@gmail.com>, 2020.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-09-01 01:41+0000\n"
+"PO-Revision-Date: 2020-08-28 12:29+0000\n"
+"Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
+"Language-Team: Chinese (Traditional) <https://translate.fedoraproject.org/projects/dnf/libdnf-dnf-4-master/zh_TW/>\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.2.1\n"
+
+#: libdnf/conf/ConfigMain.cpp:62 libdnf/conf/OptionSeconds.cpp:40
+msgid "no value specified"
+msgstr "沒有指定值"
+
+#: libdnf/conf/ConfigMain.cpp:67 libdnf/conf/OptionSeconds.cpp:48
+#, c-format
+msgid "seconds value '%s' must not be negative"
+msgstr "次要值「%s」不能是負值"
+
+#: libdnf/conf/ConfigMain.cpp:71
+#, c-format
+msgid "could not convert '%s' to bytes"
+msgstr "無法將「%s」轉換成位元組"
+
+#: libdnf/conf/ConfigMain.cpp:83 libdnf/conf/OptionSeconds.cpp:66
+#, c-format
+msgid "unknown unit '%s'"
+msgstr "未知的單位「%s」"
+
+#: libdnf/conf/ConfigMain.cpp:204 libdnf/conf/OptionEnum.cpp:83
+#: libdnf/conf/OptionNumber.cpp:88
+msgid "invalid value"
+msgstr "值無效"
+
+#: libdnf/conf/ConfigMain.cpp:207
+#, fuzzy
+#| msgid "'%s' is not an allowed value"
+msgid "value 1 is not allowed"
+msgstr "「%s」不是允許的值"
+
+#: libdnf/conf/ConfigMain.cpp:209
+msgid "negative value is not allowed"
+msgstr ""
+
+#: libdnf/conf/ConfigMain.cpp:343
+#, c-format
+msgid "percentage '%s' is out of range"
+msgstr "「%s」百分比超出範圍"
+
+#: libdnf/conf/OptionBinds.cpp:85
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" does not exist"
+msgstr "設定:含「%s」ID 的 OptionBinding 不存在"
+
+#: libdnf/conf/OptionBinds.cpp:97
+#, c-format
+msgid "Configuration: OptionBinding with id \"%s\" already exists"
+msgstr "設定:含「%s」ID 的 OptionBinding 已經存在"
+
+#: libdnf/conf/OptionBool.cpp:47
+#, c-format
+msgid "invalid boolean value '%s'"
+msgstr "無效的布林值「%s」"
+
+#: libdnf/conf/OptionEnum.cpp:72 libdnf/conf/OptionEnum.cpp:158
+#: libdnf/conf/OptionString.cpp:64 libdnf/conf/OptionStringList.cpp:59
+#, c-format
+msgid "'%s' is not an allowed value"
+msgstr "「%s」不是允許的值"
+
+#: libdnf/conf/OptionNumber.cpp:73
+#, c-format
+msgid "given value [%d] should be less than allowed value [%d]."
+msgstr "提供的值 [%d] 需要小於允許的值 [%d]。"
+
+#: libdnf/conf/OptionNumber.cpp:76
+#, c-format
+msgid "given value [%d] should be greater than allowed value [%d]."
+msgstr "提供的值 [%d] 需要大於允許的值 [%d]。"
+
+#: libdnf/conf/OptionPath.cpp:78
+#, c-format
+msgid "given path '%s' is not absolute."
+msgstr "提供的路徑「%s」並非絕對路徑。"
+
+#: libdnf/conf/OptionPath.cpp:82
+#, c-format
+msgid "given path '%s' does not exist."
+msgstr "提供的路徑「%s」不存在。"
+
+#: libdnf/conf/OptionSeconds.cpp:52
+#, c-format
+msgid "could not convert '%s' to seconds"
+msgstr "無法將「%s」轉換為秒"
+
+#: libdnf/conf/OptionString.cpp:79
+msgid "GetValue(): Value not set"
+msgstr "GetValue(): 未設定值"
+
+#: libdnf/dnf-context.cpp:3215 libdnf/dnf-context.cpp:3224
+#, fuzzy, c-format
+#| msgid "Cannot enable multiple streams for module '%s'"
+msgid "Cannot enable more streams from module '%s' at the same time"
+msgstr "無法啟用「%s」模組的多個串流"
+
+#: libdnf/dnf-context.cpp:3233 libdnf/dnf-context.cpp:3251
+#, c-format
+msgid ""
+"Cannot enable module '%1$s' stream '%2$s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3300
+#, c-format
+msgid "Modular dependency problem with Defaults: %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3303
+#, fuzzy, c-format
+#| msgid "some dependency problem"
+msgid "Modular dependency problem with the latest modules: %s"
+msgstr "有一些依賴關係問題"
+
+#: libdnf/dnf-context.cpp:3307
+#, fuzzy, c-format
+#| msgid "some dependency problem"
+msgid "Modular dependency problem: %s"
+msgstr "有一些依賴關係問題"
+
+#: libdnf/dnf-context.cpp:3330 libdnf/dnf-context.cpp:3354
+#: libdnf/dnf-context.cpp:3365 libdnf/dnf-context.cpp:3404
+#: libdnf/dnf-context.cpp:3420 libdnf/dnf-context.cpp:3452
+#: libdnf/dnf-context.cpp:3501 libdnf/dnf-context.cpp:3511
+#, fuzzy, c-format
+#| msgid "Failed to resolve: %s"
+msgid "Unable to resolve argument '%s'"
+msgstr "無法解析:%s"
+
+#: libdnf/dnf-context.cpp:3337
+#, c-format
+msgid ""
+"Only module name is required. Ignoring unneeded information in argument: "
+"'%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3351
+#, c-format
+msgid "Cannot reset module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3362
+#, c-format
+msgid "Cannot disable module '%s': State of module already modified"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3393 libdnf/dnf-context.cpp:3489
+#: libdnf/dnf-context.cpp:3670
+msgid "No modular data available"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3410
+#, c-format
+msgid "Ignoring unneeded information in argument: '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3448
+#, c-format
+msgid ""
+"Problem during enablement of dependency tree for module '%1$s' stream "
+"'%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3460
+msgid "Problems appeared for module enable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3555
+#, c-format
+msgid "No active module packages found for module spec '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3560
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "Cannot install module '%s' from fail-safe repository"
+msgstr "無法安裝 %s 和 %s 兩個模組"
+
+#: libdnf/dnf-context.cpp:3567
+#, c-format
+msgid "No profile found matching '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3621
+#, c-format
+msgid "No match for package '%s' for module spec %s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3632
+#, c-format
+msgid "Problem during install for module '%1$s' stream '%2$s': %3$s"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3641
+msgid "Problems appeared for module install request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3700
+msgid "Problems appeared for module reset request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3701 libdnf/dnf-context.cpp:3760
+msgid "Problems appeared for module disable request:"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3792
+#, c-format
+msgid ""
+"The operation would result in switching of module '%s' stream '%s' to stream"
+" '%s'"
+msgstr ""
+
+#: libdnf/dnf-context.cpp:3796
+msgid ""
+"It is not possible to switch enabled streams of a module.\n"
+"It is recommended to remove all installed content from the module, and reset the module using 'microdnf module reset <module_name>' command. After you reset the module, you can install the other stream."
+msgstr ""
+
+#: libdnf/dnf-goal.cpp:107
+msgid "Could not depsolve transaction; "
+msgstr "無法解析處理事項; "
+
+#: libdnf/dnf-goal.cpp:109
+#, c-format
+msgid "%i problem detected:\n"
+msgid_plural "%i problems detected:\n"
+msgstr[0] "偵測到 %i 個問題:\n"
+
+#: libdnf/dnf-goal.cpp:117
+#, c-format
+msgid " Problem %1$i: %2$s\n"
+msgstr " 第 %1$i 個問題:%2$s\n"
+
+#: libdnf/dnf-goal.cpp:119
+#, c-format
+msgid " Problem: %s\n"
+msgstr " 問題:%s\n"
+
+#: libdnf/dnf-rpmts.cpp:79
+#, c-format
+msgid ""
+"No available modular metadata for modular package '%s'; cannot be installed "
+"on the system"
+msgstr "「%s」模組化軟體包沒有可用的模組化中介資料;無法安裝進系統"
+
+#: libdnf/dnf-rpmts.cpp:121 libdnf/dnf-rpmts.cpp:166
+#, c-format
+msgid "signature does not verify for %s"
+msgstr "簽名無法核驗 %s"
+
+#: libdnf/dnf-rpmts.cpp:129 libdnf/dnf-rpmts.cpp:174
+#, c-format
+msgid "failed to open(generic error): %s"
+msgstr "無法開啟(一般性錯誤):%s"
+
+#: libdnf/dnf-rpmts.cpp:142
+#, c-format
+msgid "failed to verify key for %s"
+msgstr "無法核驗 %s 的金鑰"
+
+#: libdnf/dnf-rpmts.cpp:150
+#, c-format
+msgid "public key unavailable for %s"
+msgstr "無法使用 %s 的公鑰"
+
+#: libdnf/dnf-rpmts.cpp:158
+#, c-format
+msgid "signature not found for %s"
+msgstr "找不到 %s 的簽名"
+
+#: libdnf/dnf-rpmts.cpp:193
+#, c-format
+msgid "failed to add install element: %1$s [%2$i]"
+msgstr "無法加入安裝元素:%1$s [%2$i]"
+
+#: libdnf/dnf-rpmts.cpp:274
+#, c-format
+msgid "Error running transaction: %s"
+msgstr "執行處理事項時發生錯誤:%s"
+
+#: libdnf/dnf-rpmts.cpp:283
+msgid "Error running transaction and no problems were reported!"
+msgstr "執行處理事項時發生錯誤,且沒有回報問題!"
+
+#: libdnf/dnf-rpmts.cpp:346
+msgid "Fatal error, run database recovery"
+msgstr "嚴重錯誤,執行資料庫復原"
+
+#: libdnf/dnf-rpmts.cpp:355
+#, c-format
+msgid "failed to find package %s"
+msgstr "找不到 %s 軟體包"
+
+#: libdnf/dnf-rpmts.cpp:401
+#, c-format
+msgid "could not add erase element %1$s(%2$i)"
+msgstr "無法新增抹除元素 %1$s(%2$i)"
+
+#: libdnf/dnf-sack.cpp:251
+msgid "repo_add_solv() has failed."
+msgstr "repo_add_solv() 失敗。"
+
+#: libdnf/dnf-sack.cpp:415
+#, c-format
+msgid "Loading extension cache %s (%d) failed: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:429
+#, c-format
+msgid "no %1$s string for %2$s"
+msgstr "%2$s 沒有 %1$s 字串"
+
+#: libdnf/dnf-sack.cpp:439
+#, c-format
+msgid "failed to open: %s"
+msgstr "無法開啟:%s"
+
+#: libdnf/dnf-sack.cpp:518
+#, c-format
+msgid "cannot create temporary file: %s"
+msgstr "無法建立暫存檔案:%s"
+
+#: libdnf/dnf-sack.cpp:528
+#, c-format
+msgid "failed opening tmp file: %s"
+msgstr "無法開啟 tmp 檔案:%s"
+
+#: libdnf/dnf-sack.cpp:550
+#, c-format
+msgid "While writing primary cache %s repowriter write failed: %i, error: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:560
+#, fuzzy, c-format
+#| msgid "failed opening tmp file: %s"
+msgid "Failed closing tmp file %s: %s"
+msgstr "無法開啟 tmp 檔案:%s"
+
+#: libdnf/dnf-sack.cpp:570
+#, c-format
+msgid "Failed to use newly written primary cache: %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:576
+#, c-format
+msgid "Failed to use newly written primary cache: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:626
+#, c-format
+msgid "can not create temporary file %s"
+msgstr "無法建立暫存檔案 %s"
+
+#: libdnf/dnf-sack.cpp:666
+#, c-format
+msgid ""
+"While writing extension cache %s (%d): repowriter write failed: %i, error: "
+"%s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:676
+#, c-format
+msgid "While writing extension cache (%d): cannot close temporary file: %s"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:692
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d): "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:699
+#, c-format
+msgid "Failed to use newly written extension cache: %s (%d)"
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:740
+msgid "null repo md file"
+msgstr "null repo md 檔案"
+
+#: libdnf/dnf-sack.cpp:749
+#, c-format
+msgid "can not read file %1$s: %2$s"
+msgstr "無法讀取 %1$s 檔案:%2$s"
+
+#: libdnf/dnf-sack.cpp:764
+#, c-format
+msgid "While loading repository failed to use %s: "
+msgstr ""
+
+#: libdnf/dnf-sack.cpp:775
+msgid "loading of MD_TYPE_PRIMARY has failed."
+msgstr "載入 MD_TYPE_PRIMARY 失敗。"
+
+#: libdnf/dnf-sack.cpp:784
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Opening repository primary data has failed: %s"
+msgstr "正在載入插件 檔案=\"%s\""
+
+#: libdnf/dnf-sack.cpp:795
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading repomd has failed: %s"
+msgstr "正在載入插件 檔案=\"%s\""
+
+#: libdnf/dnf-sack.cpp:806
+#, fuzzy, c-format
+#| msgid "Loading plugin file=\"%s\""
+msgid "Loading primary has failed: %s"
+msgstr "正在載入插件 檔案=\"%s\""
+
+#: libdnf/dnf-sack.cpp:872
+msgid "failed to auto-detect architecture"
+msgstr "無法自動偵測架構"
+
+#: libdnf/dnf-sack.cpp:1037
+#, c-format
+msgid "failed creating cachedir %s"
+msgstr "建立快取目錄 (cachedir) %s 失敗"
+
+#: libdnf/dnf-sack.cpp:1814
+msgid "failed loading RPMDB"
+msgstr "載入 RPMDB 失敗"
+
+#: libdnf/dnf-sack.cpp:2598
+#, c-format
+msgid "No module defaults found: %s"
+msgstr "找不到模組的預設值:%s"
+
+#: libdnf/dnf-state.cpp:1184
+#, c-format
+msgid "percentage not 100: %i"
+msgstr "不是 100 百分比:%i"
+
+#: libdnf/dnf-state.cpp:1194
+#, c-format
+msgid "failed to set number steps: %i"
+msgstr "無法設定數字步驟 (number steps):%i"
+
+#: libdnf/dnf-state.cpp:1293
+msgid "cancelled by user action"
+msgstr "被使用者動作取消"
+
+#: libdnf/dnf-state.cpp:1332
+#, c-format
+msgid "done on a state %1$p that did not have a size set! [%2$s]"
+msgstr "在沒有設定大小的 %1$p 狀態上完成![%2$s]"
+
+#: libdnf/dnf-state.cpp:1357
+#, c-format
+msgid "already at 100%% state [%s]"
+msgstr "狀態已 100%% [%s]"
+
+#: libdnf/dnf-transaction.cpp:302
+#, c-format
+msgid "Sources not set when trying to ensure package %s"
+msgstr "嘗試 ensure %s 軟體包時發現來源未設定"
+
+#: libdnf/dnf-transaction.cpp:328
+#, c-format
+msgid "Failed to ensure %1$s as repo %2$s not found(%3$i repos loaded)"
+msgstr "因為找不到 %2$s 軟體庫(載入了 %3$i 個軟體庫)而無法 ensure %1$s"
+
+#: libdnf/dnf-transaction.cpp:369
+msgid "Failed to check untrusted: "
+msgstr "無法檢查不受信任: "
+
+#: libdnf/dnf-transaction.cpp:379
+#, c-format
+msgid "Downloaded file for %s not found"
+msgstr "找不到 %s 的下載檔案"
+
+#: libdnf/dnf-transaction.cpp:399
+#, c-format
+msgid "package %1$s cannot be verified and repo %2$s is GPG enabled: %3$s"
+msgstr "無法核驗 %1$s 軟體包,且 %2$s 軟體庫有啟用 GPG:%3$s"
+
+#: libdnf/dnf-transaction.cpp:833 libdnf/dnf-transaction.cpp:905
+msgid "Failed to get value for CacheDir"
+msgstr "無法取得 CacheDir 的值"
+
+#: libdnf/dnf-transaction.cpp:913
+#, c-format
+msgid "Failed to get filesystem free size for %s: "
+msgstr "無法取得 %s 的檔案系統: "
+
+#: libdnf/dnf-transaction.cpp:921
+#, c-format
+msgid "Failed to get filesystem free size for %s"
+msgstr "無法取得 %s 檔案系統的剩餘空間"
+
+#: libdnf/dnf-transaction.cpp:937
+#, c-format
+msgid "Not enough free space in %1$s: needed %2$s, available %3$s"
+msgstr "%1$s 沒有足夠的可用空間:需要 %2$s,可用 %3$s"
+
+#: libdnf/dnf-transaction.cpp:1196
+msgid "failed to set root"
+msgstr "無法設定 root"
+
+#: libdnf/dnf-transaction.cpp:1417
+#, c-format
+msgid "Error %i running transaction test"
+msgstr "錯誤 %i 執行處理事項測試"
+
+#: libdnf/dnf-transaction.cpp:1441
+#, c-format
+msgid "Error %i opening rpm database"
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1449 libdnf/dnf-transaction.cpp:1495
+msgid "The rpmdbCookie() function did not return cookie of rpm database."
+msgstr ""
+
+#: libdnf/dnf-transaction.cpp:1464
+#, c-format
+msgid "Error %i running transaction"
+msgstr "錯誤 %i 執行處理事項"
+
+#: libdnf/dnf-transaction.cpp:1480
+#, c-format
+msgid "Transaction did not go to writing phase, but returned no error(%i)"
+msgstr "處理事項沒有進入寫入階段,但沒有傳回錯誤 (%i)"
+
+#: libdnf/dnf-utils.cpp:111 libdnf/hy-iutil.cpp:487
+#, c-format
+msgid "cannot open directory %1$s: %2$s"
+msgstr "無法開啟 %1$s 目錄:%2$s"
+
+#: libdnf/dnf-utils.cpp:136
+#, c-format
+msgid "failed to remove %s"
+msgstr "無法移除 %s"
+
+#: libdnf/goal/Goal.cpp:78
+msgid "Ill-formed Selector, presence of multiple match objects in the filter"
+msgstr "選擇器格式有誤,過濾器包含多個符合物件"
+
+#: libdnf/goal/Goal.cpp:79
+msgid "Ill-formed Selector used for the operation, incorrect comparison type"
+msgstr "用於此動作的選擇器格式有誤,不正確的比較類型"
+
+#: libdnf/goal/Goal.cpp:90
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "不屬於 distupgrade 軟體庫"
+
+#: libdnf/goal/Goal.cpp:91
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:92
+msgid "problem with installed package "
+msgstr "安裝的軟體包有問題 "
+
+#: libdnf/goal/Goal.cpp:93 libdnf/goal/Goal.cpp:120
+msgid "conflicting requests"
+msgstr "有衝突的要求"
+
+#: libdnf/goal/Goal.cpp:94 libdnf/goal/Goal.cpp:121
+msgid "unsupported request"
+msgstr "不支援的要求"
+
+#: libdnf/goal/Goal.cpp:95 libdnf/goal/Goal.cpp:122
+msgid "nothing provides requested "
+msgstr "沒有軟體包提供要求項目 "
+
+#: libdnf/goal/Goal.cpp:96
+#, c-format
+msgid "package %s does not exist"
+msgstr "%s 軟體包不存在"
+
+#: libdnf/goal/Goal.cpp:97 libdnf/goal/Goal.cpp:124
+msgid " is provided by the system"
+msgstr " 由系統提供"
+
+#: libdnf/goal/Goal.cpp:98 libdnf/goal/Goal.cpp:125
+msgid "some dependency problem"
+msgstr "有一些依賴關係問題"
+
+#: libdnf/goal/Goal.cpp:99
+msgid "cannot install the best update candidate for package "
+msgstr "無法安裝軟體包的最佳更新候選 "
+
+#: libdnf/goal/Goal.cpp:100 libdnf/goal/Goal.cpp:127
+msgid "cannot install the best candidate for the job"
+msgstr "無法安裝工作的最佳候選"
+
+#: libdnf/goal/Goal.cpp:101
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by modular filtering"
+msgid "package %s from %s is filtered out by modular filtering"
+msgstr "%s 軟體包已經被模組化過濾器濾掉"
+
+#: libdnf/goal/Goal.cpp:102
+#, fuzzy, c-format
+#| msgid "package %s does not have a compatible architecture"
+msgid "package %s from %s does not have a compatible architecture"
+msgstr "%s 軟體包沒有相容架構"
+
+#: libdnf/goal/Goal.cpp:103
+#, fuzzy, c-format
+#| msgid "package %s is not installable"
+msgid "package %s from %s is not installable"
+msgstr "不能安裝 %s 軟體包"
+
+#: libdnf/goal/Goal.cpp:104
+#, fuzzy, c-format
+#| msgid "package %s is filtered out by exclude filtering"
+msgid "package %s from %s is filtered out by exclude filtering"
+msgstr "%s 軟體包已被排除過濾器濾掉"
+
+#: libdnf/goal/Goal.cpp:105
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by %s"
+msgid "nothing provides %s needed by %s from %s"
+msgstr "沒有軟體包提供 %s (%s 需要)"
+
+#: libdnf/goal/Goal.cpp:106
+#, fuzzy, c-format
+#| msgid "cannot install both %s and %s"
+msgid "cannot install both %s from %s and %s from %s"
+msgstr "無法安裝 %s 和 %s 兩個"
+
+#: libdnf/goal/Goal.cpp:107
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by %s"
+msgid "package %s from %s conflicts with %s provided by %s from %s"
+msgstr "%s 軟體包與 %s (由 %s 提供) 衝突"
+
+#: libdnf/goal/Goal.cpp:108
+#, fuzzy, c-format
+#| msgid "package %s obsoletes %s provided by %s"
+msgid "package %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s 軟體包棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:109
+#, fuzzy, c-format
+#| msgid "installed package %s obsoletes %s provided by %s"
+msgid "installed package %s obsoletes %s provided by %s from %s"
+msgstr "安裝的 %s 軟體包棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:110
+#, fuzzy, c-format
+#| msgid "package %s implicitly obsoletes %s provided by %s"
+msgid "package %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "%s 軟體包隱式棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:111
+#, fuzzy, c-format
+#| msgid ""
+#| "package %s requires %s, but none of the providers can be installed"
+msgid ""
+"package %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s 軟體包需要 %s,但無法安裝任何一個提供者"
+
+#: libdnf/goal/Goal.cpp:112
+#, fuzzy, c-format
+#| msgid "package %s conflicts with %s provided by itself"
+msgid "package %s from %s conflicts with %s provided by itself"
+msgstr "%s 軟體包與自身提供的 %s 衝突"
+
+#: libdnf/goal/Goal.cpp:113
+#, fuzzy, c-format
+#| msgid "both package %s and %s obsolete %s"
+msgid "both package %s from %s and %s from %s obsolete %s"
+msgstr "%s 和 %s 兩個軟體包棄用了 %s"
+
+#: libdnf/goal/Goal.cpp:117
+#, fuzzy, c-format
+#| msgid " does not belong to a distupgrade repository"
+msgid "%s from %s does not belong to a distupgrade repository"
+msgstr "不屬於 distupgrade 軟體庫"
+
+#: libdnf/goal/Goal.cpp:118
+#, c-format
+msgid "%s from %s has inferior architecture"
+msgstr ""
+
+#: libdnf/goal/Goal.cpp:119
+msgid "problem with installed module "
+msgstr "安裝的模組有問題 "
+
+#: libdnf/goal/Goal.cpp:123
+#, c-format
+msgid "module %s does not exist"
+msgstr "%s 模組不存在"
+
+#: libdnf/goal/Goal.cpp:126
+msgid "cannot install the best update candidate for module "
+msgstr "無法安裝模組的最佳更新候選 "
+
+#: libdnf/goal/Goal.cpp:128 libdnf/goal/Goal.cpp:131
+#, fuzzy, c-format
+#| msgid "module %s is disabled"
+msgid "module %s from %s is disabled"
+msgstr "已停用 %s 模組"
+
+#: libdnf/goal/Goal.cpp:129
+#, fuzzy, c-format
+#| msgid "module %s does not have a compatible architecture"
+msgid "module %s from %s does not have a compatible architecture"
+msgstr "%s 模組沒有相容的架構"
+
+#: libdnf/goal/Goal.cpp:130
+#, fuzzy, c-format
+#| msgid "module %s is not installable"
+msgid "module %s from %s is not installable"
+msgstr "無法安裝 %s 模組"
+
+#: libdnf/goal/Goal.cpp:132
+#, fuzzy, c-format
+#| msgid "nothing provides %s needed by module %s"
+msgid "nothing provides %s needed by module %s from %s"
+msgstr "沒有軟體包提供 %s (%s 模組需要)"
+
+#: libdnf/goal/Goal.cpp:133
+#, fuzzy, c-format
+#| msgid "cannot install both modules %s and %s"
+msgid "cannot install both modules %s from %s and %s from %s"
+msgstr "無法安裝 %s 和 %s 兩個模組"
+
+#: libdnf/goal/Goal.cpp:134
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by %s"
+msgid "module %s from %s conflicts with %s provided by %s from %s"
+msgstr "%s 模組與 %s (由 %s 提供) 衝突"
+
+#: libdnf/goal/Goal.cpp:135
+#, fuzzy, c-format
+#| msgid "module %s obsoletes %s provided by %s"
+msgid "module %s from %s obsoletes %s provided by %s from %s"
+msgstr "%s 模組棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:136
+#, fuzzy, c-format
+#| msgid "installed module %s obsoletes %s provided by %s"
+msgid "installed module %s obsoletes %s provided by %s from %s"
+msgstr "安裝的 %s 模組棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:137
+#, fuzzy, c-format
+#| msgid "module %s implicitly obsoletes %s provided by %s"
+msgid "module %s from %s implicitly obsoletes %s provided by %s from %s"
+msgstr "%s 模組隱式棄用了 %s (由 %s 提供)"
+
+#: libdnf/goal/Goal.cpp:138
+#, fuzzy, c-format
+#| msgid ""
+#| "module %s requires %s, but none of the providers can be installed"
+msgid ""
+"module %s from %s requires %s, but none of the providers can be installed"
+msgstr "%s 模組需要 %s,但無法安裝任何一個提供者"
+
+#: libdnf/goal/Goal.cpp:139
+#, fuzzy, c-format
+#| msgid "module %s conflicts with %s provided by itself"
+msgid "module %s from %s conflicts with %s provided by itself"
+msgstr "%s 模組與自身提供的 %s 衝突"
+
+#: libdnf/goal/Goal.cpp:140
+#, fuzzy, c-format
+#| msgid "both module %s and %s obsolete %s"
+msgid "both module %s from %s and %s from %s obsolete %s"
+msgstr "%s 和 %s 兩個模組棄用了 %s"
+
+#: libdnf/goal/Goal.cpp:1168
+msgid "no solver set"
+msgstr "未設定解析器"
+
+#: libdnf/goal/Goal.cpp:1173
+#, c-format
+msgid "failed to make %s absolute"
+msgstr "無法使 %s 絕對"
+
+#: libdnf/goal/Goal.cpp:1180
+#, c-format
+msgid "failed writing debugdata to %1$s: %2$s"
+msgstr "無法將除錯資料寫入 %1$s:%2$s"
+
+#: libdnf/goal/Goal.cpp:1192
+msgid "no solv in the goal"
+msgstr "goal 中沒有 solv"
+
+#: libdnf/goal/Goal.cpp:1194
+msgid "no solution, cannot remove protected package"
+msgstr "沒有解決方案,無法移除受保護的軟體包"
+
+#: libdnf/goal/Goal.cpp:1197
+msgid "no solution possible"
+msgstr "沒有可行的解決方案"
+
+#: libdnf/goal/Goal.cpp:1323
+#, fuzzy
+#| msgid " Problem: %s\n"
+msgid "Problem: "
+msgstr "問題:%s "
+
+#: libdnf/goal/Goal.cpp:1328
+#, fuzzy, c-format
+#| msgid " Problem: %s\n"
+msgid "Problem %d: "
+msgstr "問題:%s "
+
+#: libdnf/goal/Goal.cpp:1661
+msgid ""
+"The operation would result in removing the following protected packages: "
+msgstr "此動作可能會導致移除以下受保護的軟體包: "
+
+#: libdnf/hy-iutil.cpp:181
+#, c-format
+msgid "Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"
+msgstr ""
+
+#: libdnf/hy-iutil.cpp:410
+#, c-format
+msgid "Failed renaming %1$s to %2$s: %3$s"
+msgstr "重新命名 %1$s 到 %2$s 失敗:%3$s"
+
+#: libdnf/hy-iutil.cpp:418
+#, c-format
+msgid "Failed setting perms on %1$s: %2$s"
+msgstr "設定 %1$s 權限失敗:%2$s"
+
+#: libdnf/hy-iutil.cpp:464
+#, c-format
+msgid "cannot create directory %1$s: %2$s"
+msgstr "無法建立 %1$s 目錄:%2$s"
+
+#: libdnf/hy-iutil.cpp:499
+#, c-format
+msgid "cannot stat path %1$s: %2$s"
+msgstr "無法 stat %1$s 路徑:%2$s"
+
+#: libdnf/module/ModulePackage.cpp:604
+#, c-format
+msgid "Invalid format of Platform module: %s"
+msgstr "Platform 模組的格式無效:%s"
+
+#: libdnf/module/ModulePackage.cpp:619
+msgid "Multiple module platforms provided by available packages\n"
+msgstr "可用的軟體包提供了多個模組平臺\n"
+
+#: libdnf/module/ModulePackage.cpp:632
+msgid "Multiple module platforms provided by installed packages\n"
+msgstr "安裝的軟體包提供了多個模組平臺\n"
+
+#: libdnf/module/ModulePackage.cpp:659
+#, c-format
+msgid "Detection of Platform Module in %s failed: %s"
+msgstr "偵測 %s 中的 Platform 模組失敗:%s"
+
+#: libdnf/module/ModulePackage.cpp:668
+#, c-format
+msgid "Missing PLATFORM_ID in %s"
+msgstr "%s 缺少 PLATFORM_ID"
+
+#: libdnf/module/ModulePackage.cpp:673
+msgid "No valid Platform ID detected"
+msgstr "未偵測到有效的 Platform ID"
+
+#: libdnf/module/ModulePackageContainer.cpp:107
+#, c-format
+msgid "Cannot enable multiple streams for module '%s'"
+msgstr "無法啟用「%s」模組的多個串流"
+
+#: libdnf/module/ModulePackageContainer.cpp:339
+#, c-format
+msgid "Conflicting defaults with repo '%s': %s"
+msgstr "預設值與「%s」軟體庫衝突:%s"
+
+#: libdnf/module/ModulePackageContainer.cpp:923
+msgid "Installing module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:938
+msgid "Disabling module profiles:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:953
+msgid "Enabling module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:967
+msgid "Switching module streams:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:985
+msgid "Disabling modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:996
+msgid "Resetting modules:\n"
+msgstr ""
+
+#: libdnf/module/ModulePackageContainer.cpp:1710
+#, c-format
+msgid "Unable to load modular Fail-Safe data at '%s'"
+msgstr "無法載入位於「%s」的模組化防故障資料"
+
+#: libdnf/module/ModulePackageContainer.cpp:1716
+#, c-format
+msgid "Unable to load modular Fail-Safe data for module '%s:%s'"
+msgstr "無法載入「%s:%s」模組的模組化防故障資料"
+
+#: libdnf/module/ModulePackageContainer.cpp:1797
+#, c-format
+msgid "Unable to create directory \"%s\" for modular Fail Safe data: %s"
+msgstr "無法為模組化防故障資料建立「%s」目錄:%s"
+
+#: libdnf/module/ModulePackageContainer.cpp:1813
+#, c-format
+msgid "Unable to save a modular Fail Safe data to '%s'"
+msgstr "無法儲存模組化防故障資料至「%s」"
+
+#: libdnf/module/ModulePackageContainer.cpp:1836
+#, c-format
+msgid "Unable to remove a modular Fail Safe data in '%s'"
+msgstr "無法移除「%s」的模組化防故障資料"
+
+#: libdnf/module/ModulePackageContainer.cpp:1868
+#, c-format
+msgid ""
+"Unable to apply modular obsoletes to '%s:%s' because target module '%s' is "
+"disabled"
+msgstr ""
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:86
+#, c-format
+msgid "Failed to update from string: %s"
+msgstr "無法從字串更新:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:110
+#, c-format
+msgid "Failed to resolve: %s"
+msgstr "無法解析:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:115
+#, c-format
+msgid "There were errors while resolving modular defaults: %s"
+msgstr "解析模組化預設值時發生錯誤:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:120
+#, c-format
+msgid "Failed to upgrade defaults: %s"
+msgstr "無法升級預設值:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:123
+#, c-format
+msgid "Failed to upgrade streams: %s"
+msgstr "無法升級串流:%s"
+
+#: libdnf/module/modulemd/ModuleMetadata.cpp:221
+#, c-format
+msgid "Cannot retrieve module obsoletes because no stream matching %s: %s"
+msgstr ""
+
+#: libdnf/plugin/plugin.cpp:46
+#, c-format
+msgid "Can't load shared library \"%s\": %s"
+msgstr "無法載入「%s」共用函式庫:%s"
+
+#: libdnf/plugin/plugin.cpp:61 libdnf/plugin/plugin.cpp:67
+#: libdnf/plugin/plugin.cpp:73 libdnf/plugin/plugin.cpp:79
+#, c-format
+msgid "Can't obtain address of symbol \"%s\": %s"
+msgstr "無法取得「%s」符號的地址:%s"
+
+#: libdnf/plugin/plugin.cpp:86
+#, c-format
+msgid "Loading plugin file=\"%s\""
+msgstr "正在載入插件 檔案=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:89
+#, c-format
+msgid "Loaded plugin name=\"%s\", version=\"%s\""
+msgstr "已載入插件 名稱=\"%s\",版本=\"%s\""
+
+#: libdnf/plugin/plugin.cpp:96
+msgid "Plugins::loadPlugins() dirPath cannot be empty"
+msgstr "Plugins::loadPlugins() dirPath 不可空白"
+
+#: libdnf/plugin/plugin.cpp:105
+#, c-format
+msgid "Can't read plugin directory \"%s\": %s"
+msgstr "無法讀取「%s」插件目錄:%s"
+
+#: libdnf/plugin/plugin.cpp:114
+#, c-format
+msgid "Can't load plugin \"%s\": %s"
+msgstr "無法載入「%s」插件:%s"
+
+#: libdnf/repo/Crypto.cpp:99 libdnf/repo/Repo.cpp:955
+#: libdnf/repo/Repo.cpp:1029 libdnf/repo/Repo.cpp:1072
+#, c-format
+msgid "Cannot create repo temporary directory \"%s\": %s"
+msgstr "無法建立軟體庫的暫存目錄「%s」:%s"
+
+#: libdnf/repo/DependencySplitter.cpp:51
+msgid ""
+"Using '==' operator in reldeps can result in an undefined behavior. It is "
+"deprecated and the support will be dropped in future versions. Use '=' "
+"operator instead."
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:314
+#, c-format
+msgid "Repository %s has no mirror or baseurl set."
+msgstr "%s 軟體庫沒有設定鏡像站或基礎 URL。"
+
+#: libdnf/repo/Repo.cpp:323
+#, c-format
+msgid "Repository '%s' has unsupported type: 'type=%s', skipping."
+msgstr "「%s」軟體庫有不支援的類型:「類型=%s」,跳過。"
+
+#: libdnf/repo/Repo.cpp:484 libdnf/repo/Repo.cpp:605 libdnf/repo/Repo.cpp:636
+#: libdnf/repo/Repo.cpp:1193
+#, c-format
+msgid "repo '%s': 'basecachedir' is not set"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:507
+msgid ""
+"Maximum download speed is lower than minimum. Please change configuration of"
+" minrate or throttle"
+msgstr "最大下載速度低於最小下載速度。請調整 minrate 或 throttle 的設定檔"
+
+#: libdnf/repo/Repo.cpp:541
+#, c-format
+msgid "repo '%s': 'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:543
+msgid "'proxy_username' is set but not 'proxy_password'"
+msgstr ""
+
+#: libdnf/repo/Repo.cpp:624
+#, c-format
+msgid "Cannot find a valid baseurl for repo: %s"
+msgstr "找不到軟體庫的有效基礎 URL:%s"
+
+#: libdnf/repo/Repo.cpp:669
+#, c-format
+msgid "Failed to retrieve GPG key for repo '%s': %s"
+msgstr "無法取出「%s」軟體庫的 GPG 金鑰:%s"
+
+#: libdnf/repo/Repo.cpp:690
+#, c-format
+msgid "repo %s: 0x%s already imported"
+msgstr "%s 軟體庫:0x%s 早已匯入"
+
+#: libdnf/repo/Repo.cpp:704 libdnf/utils/filesystem.cpp:79
+#, fuzzy, c-format
+#| msgid "Cannot create directory \"%s\": %s"
+msgid "Failed to create directory \"%s\": %d - %s"
+msgstr "無法建立「%s」目錄:%s"
+
+#: libdnf/repo/Repo.cpp:712
+#, c-format
+msgid "repo %s: imported key 0x%s."
+msgstr "%s 軟體庫:已匯入 0x%s 金鑰。"
+
+#: libdnf/repo/Repo.cpp:969
+#, c-format
+msgid "reviving: repo '%s' skipped, no metalink."
+msgstr "reviving:跳過「%s」軟體庫,沒有 metalink。"
+
+#: libdnf/repo/Repo.cpp:988
+#, c-format
+msgid "reviving: repo '%s' skipped, no usable hash."
+msgstr "reviving:跳過「%s」軟體庫,沒有可用的雜湊值。"
+
+#: libdnf/repo/Repo.cpp:1011
+#, c-format
+msgid "reviving: failed for '%s', mismatched %s sum."
+msgstr "reviving:「%s」失敗,%s 總和不符。"
+
+#: libdnf/repo/Repo.cpp:1017
+#, c-format
+msgid "reviving: '%s' can be revived - metalink checksums match."
+msgstr "reviving:可以重生 (revive)「%s」- metalink 總和檢查碼符合。"
+
+#: libdnf/repo/Repo.cpp:1046
+#, c-format
+msgid "reviving: '%s' can be revived - repomd matches."
+msgstr "reviving:可以重生 (revive)「%s」- repomd 符合。"
+
+#: libdnf/repo/Repo.cpp:1048
+#, c-format
+msgid "reviving: failed for '%s', mismatched repomd."
+msgstr "reviving:「%s」失敗,repomd 不符。"
+
+#: libdnf/repo/Repo.cpp:1066
+#, c-format
+msgid "Cannot create repo destination directory \"%s\": %s"
+msgstr "無法建立軟體庫的目的地目錄「%s」:%s"
+
+#: libdnf/repo/Repo.cpp:1086
+#, c-format
+msgid "Cannot create directory \"%s\": %s"
+msgstr "無法建立「%s」目錄:%s"
+
+#: libdnf/repo/Repo.cpp:1109
+#, c-format
+msgid "Cannot rename directory \"%s\" to \"%s\": %s"
+msgstr "無法將「%s」目錄重新命名至「%s」:%s"
+
+#: libdnf/repo/Repo.cpp:1132
+#, c-format
+msgid "repo: using cache for: %s"
+msgstr "repo:使用下述的快取:%s"
+
+#: libdnf/repo/Repo.cpp:1144
+#, c-format
+msgid "Cache-only enabled but no cache for '%s'"
+msgstr "啟用了「只使用快取」,但是沒有「%s」的快取。"
+
+#: libdnf/repo/Repo.cpp:1148
+#, c-format
+msgid "repo: downloading from remote: %s"
+msgstr "repo:從遠端下載:%s"
+
+#: libdnf/repo/Repo.cpp:1155
+#, c-format
+msgid "Failed to download metadata for repo '%s': %s"
+msgstr "無法下載「%s」軟體庫的中介資料:%s"
+
+#: libdnf/repo/Repo.cpp:1181
+msgid "getCachedir(): Computation of SHA256 failed"
+msgstr "getCachedir(): 計算 SHA256 失敗"
+
+#: libdnf/repo/Repo.cpp:1209
+#, c-format
+msgid "Cannot create persistdir \"%s\": %s"
+msgstr "無法建立「%s」persistdir:%s"
+
+#: libdnf/repo/Repo.cpp:1586
+msgid "resume cannot be used simultaneously with the byterangestart param"
+msgstr "resume 不可與 byterangestart 參數同時使用"
+
+#: libdnf/repo/Repo.cpp:1603
+#, c-format
+msgid "PackageTarget initialization failed: %s"
+msgstr "PackageTarget 初始化失敗:%s"
+
+#: libdnf/repo/Repo.cpp:1709
+#, c-format
+msgid "Cannot open %s: %s"
+msgstr "無法開啟 %s:%s"
+
+#: libdnf/repo/Repo.cpp:1753
+#, c-format
+msgid "Log handler with id %ld doesn't exist"
+msgstr "有 ID %ld 的記錄處理器不存在"
+
+#: libdnf/transaction/Swdb.cpp:173
+msgid "In progress"
+msgstr "正在進行"
+
+#: libdnf/transaction/Swdb.cpp:187 libdnf/transaction/Swdb.cpp:215
+#: libdnf/transaction/Swdb.cpp:227 libdnf/transaction/Swdb.cpp:244
+#: libdnf/transaction/Swdb.cpp:383 libdnf/transaction/Swdb.cpp:393
+msgid "Not in progress"
+msgstr "未在進行"
+
+#: libdnf/transaction/Swdb.cpp:254
+msgid "No transaction in progress"
+msgstr "沒有正在進行的處理事項"
+
+#: libdnf/transaction/TransactionItem.cpp:146
+msgid "Attempt to insert transaction item into completed transaction"
+msgstr "嘗試將處理事項項目插入已完成的處理事項中"
+
+#: libdnf/transaction/TransactionItem.cpp:217
+msgid "Attempt to update transaction item in completed transaction"
+msgstr "嘗試更新已完成處理事項中的處理事項項目"
+
+#: libdnf/transaction/Transformer.cpp:76
+msgid "Database Corrupted: no row 'version' in table 'config'"
+msgstr "資料庫損壞:'config' 資料表中沒有 'version' 列"
+
+#: libdnf/transaction/Transformer.cpp:681
+msgid "Transformer: can't open history persist dir"
+msgstr "Transformer:無法開啟歷史 persist 目錄"
+
+#: libdnf/transaction/Transformer.cpp:694
+msgid "Couldn't find a history database"
+msgstr "找不到歷史資料庫"
+
+#: libdnf/transaction/private/Transaction.cpp:41
+msgid "Transaction has already began!"
+msgstr "處理事項早已開始!"
+
+#: libdnf/transaction/private/Transaction.cpp:58
+#, c-format
+msgid "TransactionItem state is not set: %s"
+msgstr "未設定 TransactionItem 狀態:%s"
+
+#: libdnf/transaction/private/Transaction.cpp:243
+msgid "Can't add console output to unsaved transaction"
+msgstr "無法將控制台輸出加進未儲存的處理事項"
+
+#, c-format
+#~ msgid "%s: gpgme_data_new_from_fd(): %s"
+#~ msgstr "%s: gpgme_data_new_from_fd(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_op_import(): %s"
+#~ msgstr "%s: gpgme_op_import(): %s"
+
+#, c-format
+#~ msgid "%s: gpgme_ctx_set_engine_info(): %s"
+#~ msgstr "%s: gpgme_ctx_set_engine_info(): %s"
+
+#, c-format
+#~ msgid "can not list keys: %s"
+#~ msgstr "無法列舉設定鍵:%s"
+
+#~ msgid "failed to add solv"
+#~ msgstr "無法加入 solv"
+
+#~ msgid "write_main() failed writing data: %i"
+#~ msgstr "write_main() 無法寫入資料:%i"
+
+#~ msgid "write_main() failed to re-load written solv file"
+#~ msgstr "write_main() 無法重新載入寫入的 solv 檔案"
+
+#~ msgid "write_ext(%1$d) has failed: %2$d"
+#~ msgstr "write_ext(%1$d) 失敗:%2$d"
+
+#~ msgid "repo_add_repomdxml/rpmmd() has failed."
+#~ msgstr "repo_add_repomdxml/rpmmd() 失敗。"
+
+#, fuzzy
+#~ msgid "Failed to parse module artifact NEVRA '%s'"
+#~ msgstr "無法升級預設值:%s"
+
+#~ msgid "Bad id for repo: %s, byte = %s %d"
+#~ msgstr "軟體庫的 ID 無效:%s,位元組 = %s %d"
+
+#~ msgid "failed calculating RPMDB checksum"
+#~ msgstr "計算RPMDB校驗和失敗"
--- /dev/null
+if(${PYTHON_VERSION_MAJOR} STREQUAL "2")
+ message("Building for python2")
+ set(HAWKEY_MODULE_NAME "_hawkeymodule")
+else()
+ message("Building for python3")
+ set(HAWKEY_MODULE_NAME "_hawkey")
+endif()
+
+find_package(PythonInstDir)
+include_directories(${PYTHON_INCLUDE_PATH})
+include_directories("${CMAKE_SOURCE_DIR}/libdnf")
+
+message(STATUS "Python install dir is ${PYTHON_INSTALL_DIR}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-strict-aliasing")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-strict-aliasing")
+
+set(hawkey_COPIES __init__.py)
+file(COPY ${hawkey_COPIES} DESTINATION ./hawkey/)
+
+set(hawkeymodule_SRCS
+ advisory-py.cpp
+ advisorypkg-py.cpp
+ advisoryref-py.cpp
+ exception-py.cpp
+ goal-py.cpp
+ hawkeymodule.cpp
+ iutil-py.cpp
+ nsvcap-py.cpp
+ nevra-py.cpp
+ package-py.cpp
+ packagedelta-py.cpp
+ query-py.cpp
+ reldep-py.cpp
+ repo-py.cpp
+ sack-py.cpp
+ selector-py.cpp
+ subject-py.cpp
+ pycomp.cpp
+)
+
+add_library(_hawkeymodule SHARED ${hawkeymodule_SRCS})
+set_target_properties(_hawkeymodule PROPERTIES PREFIX "")
+set_target_properties(_hawkeymodule PROPERTIES OUTPUT_NAME ${HAWKEY_MODULE_NAME})
+set_target_properties(_hawkeymodule PROPERTIES LIBRARY_OUTPUT_DIRECTORY "./hawkey")
+target_link_libraries(_hawkeymodule libdnf ${SOLV_LIBRARY} ${SOLVEXT_LIBRARY})
+target_link_libraries(_hawkeymodule ${PYTHON_LIBRARY})
+
+install(FILES __init__.py DESTINATION ${PYTHON_INSTALL_DIR}/hawkey)
+install(TARGETS _hawkeymodule LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}/hawkey)
+
+IF (WITH_TESTS)
+add_subdirectory(tests)
+ENDIF()
--- /dev/null
+#
+# Copyright (C) 2012-2019 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from sys import version_info as python_version
+
+import collections
+import functools
+import logging
+import operator
+import time
+import warnings
+
+import libdnf.transaction
+
+from . import _hawkey
+
+__all__ = [
+ # version info
+ 'VERSION', 'VERSION_MAJOR', 'VERSION_MINOR', 'VERSION_PATCH',
+ # submodules
+ 'test',
+ # constants
+ 'CHKSUM_MD5', 'CHKSUM_SHA1', 'CHKSUM_SHA256', 'CHKSUM_SHA384', 'CHKSUM_SHA512',
+ 'ICASE', 'CMDLINE_REPO_NAME', 'MODULE_FAIL_SAFE_REPO_NAME', 'SYSTEM_REPO_NAME', 'REASON_DEP',
+ 'REASON_USER', 'REASON_CLEAN', 'REASON_WEAKDEP', 'FORM_NEVRA', 'FORM_NEVR', 'FORM_NEV',
+ 'FORM_NA', 'FORM_NAME', 'FORM_ALL', 'MODULE_FORM_NSVCAP', 'MODULE_FORM_NSVCA',
+ 'MODULE_FORM_NSVAP', 'MODULE_FORM_NSVA', 'MODULE_FORM_NSAP', 'MODULE_FORM_NSA',
+ 'MODULE_FORM_NSVCP', 'MODULE_FORM_NSVP', 'MODULE_FORM_NSVC', 'MODULE_FORM_NSV',
+ 'MODULE_FORM_NSP', 'MODULE_FORM_NS', 'MODULE_FORM_NAP', 'MODULE_FORM_NA',
+ 'MODULE_FORM_NP', 'MODULE_FORM_N'
+ # exceptions
+ 'ArchException', 'Exception', 'QueryException', 'RuntimeException',
+ 'ValueException',
+ # functions
+ 'chksum_name', 'chksum_type', 'split_nevra', 'convert_hawkey_reason',
+ # classes
+ 'Goal', 'NEVRA', 'NSVCAP', 'Package', 'Query', 'Repo', 'Sack', 'Selector', 'Subject']
+
+NEVRA = _hawkey.NEVRA
+Query = _hawkey.Query
+Selector = _hawkey.Selector
+
+VERSION_MAJOR = _hawkey.VERSION_MAJOR
+VERSION_MINOR = _hawkey.VERSION_MINOR
+VERSION_PATCH = _hawkey.VERSION_PATCH
+VERSION = u"%d.%d.%d" % (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
+
+SYSTEM_REPO_NAME = _hawkey.SYSTEM_REPO_NAME
+CMDLINE_REPO_NAME = _hawkey.CMDLINE_REPO_NAME
+MODULE_FAIL_SAFE_REPO_NAME = _hawkey.MODULE_FAIL_SAFE_REPO_NAME
+
+FORM_NEVRA = _hawkey.FORM_NEVRA
+FORM_NEVR = _hawkey.FORM_NEVR
+FORM_NEV = _hawkey.FORM_NEV
+FORM_NA = _hawkey.FORM_NA
+FORM_NAME = _hawkey.FORM_NAME
+
+MODULE_FORM_NSVCAP = _hawkey.MODULE_FORM_NSVCAP
+MODULE_FORM_NSVCA = _hawkey.MODULE_FORM_NSVCA
+MODULE_FORM_NSVAP = _hawkey.MODULE_FORM_NSVAP
+MODULE_FORM_NSVA = _hawkey.MODULE_FORM_NSVA
+MODULE_FORM_NSAP = _hawkey.MODULE_FORM_NSAP
+MODULE_FORM_NSA = _hawkey.MODULE_FORM_NSA
+MODULE_FORM_NSVCP = _hawkey.MODULE_FORM_NSVCP
+MODULE_FORM_NSVP = _hawkey.MODULE_FORM_NSVP
+MODULE_FORM_NSVC = _hawkey.MODULE_FORM_NSVC
+MODULE_FORM_NSV = _hawkey.MODULE_FORM_NSV
+MODULE_FORM_NSP = _hawkey.MODULE_FORM_NSP
+MODULE_FORM_NS = _hawkey.MODULE_FORM_NS
+MODULE_FORM_NAP = _hawkey.MODULE_FORM_NAP
+MODULE_FORM_NA = _hawkey.MODULE_FORM_NA
+MODULE_FORM_NP = _hawkey.MODULE_FORM_NP
+MODULE_FORM_N = _hawkey.MODULE_FORM_N
+
+ICASE = _hawkey.ICASE
+EQ = _hawkey.EQ
+LT = _hawkey.LT
+GT = _hawkey.GT
+
+APPLY_EXCLUDES = _hawkey.APPLY_EXCLUDES
+IGNORE_MODULAR_EXCLUDES = _hawkey.IGNORE_MODULAR_EXCLUDES
+IGNORE_REGULAR_EXCLUDES = _hawkey.IGNORE_REGULAR_EXCLUDES
+IGNORE_EXCLUDES = _hawkey.IGNORE_EXCLUDES
+
+CHKSUM_MD5 = _hawkey.CHKSUM_MD5
+CHKSUM_SHA1 = _hawkey.CHKSUM_SHA1
+CHKSUM_SHA256 = _hawkey.CHKSUM_SHA256
+CHKSUM_SHA384 = _hawkey.CHKSUM_SHA384
+CHKSUM_SHA512 = _hawkey.CHKSUM_SHA512
+
+REASON_DEP = _hawkey.REASON_DEP
+REASON_USER = _hawkey.REASON_USER
+REASON_CLEAN = _hawkey.REASON_CLEAN
+REASON_WEAKDEP = _hawkey.REASON_WEAKDEP
+
+def convert_hawkey_reason(hawkey_reason):
+ if hawkey_reason == REASON_USER:
+ return libdnf.transaction.TransactionItemReason_USER
+ if hawkey_reason == REASON_DEP:
+ return libdnf.transaction.TransactionItemReason_DEPENDENCY
+ if hawkey_reason == REASON_CLEAN:
+ return libdnf.transaction.TransactionItemReason_CLEAN
+ if hawkey_reason == REASON_WEAKDEP:
+ return libdnf.transaction.TransactionItemReason_WEAK_DEPENDENCY
+ return libdnf.transaction.TransactionItemReason_UNKNOWN
+
+ADVISORY_UNKNOWN = _hawkey.ADVISORY_UNKNOWN
+ADVISORY_SECURITY = _hawkey.ADVISORY_SECURITY
+ADVISORY_BUGFIX = _hawkey.ADVISORY_BUGFIX
+ADVISORY_ENHANCEMENT = _hawkey.ADVISORY_ENHANCEMENT
+ADVISORY_NEWPACKAGE = _hawkey.ADVISORY_NEWPACKAGE
+
+REFERENCE_UNKNOWN = _hawkey.REFERENCE_UNKNOWN
+REFERENCE_BUGZILLA = _hawkey.REFERENCE_BUGZILLA
+REFERENCE_CVE = _hawkey.REFERENCE_CVE
+REFERENCE_VENDOR = _hawkey.REFERENCE_VENDOR
+
+Package = _hawkey.Package
+Reldep = _hawkey.Reldep
+Sack = _hawkey.Sack
+
+Exception = _hawkey.Exception
+QueryException = _hawkey.QueryException
+ValueException = _hawkey.ValueException
+ArchException = _hawkey.ArchException
+RuntimeException = _hawkey.RuntimeException
+
+chksum_name = _hawkey.chksum_name
+chksum_type = _hawkey.chksum_type
+detect_arch = _hawkey.detect_arch
+
+ERASE = _hawkey.ERASE
+DISTUPGRADE = _hawkey.DISTUPGRADE
+DISTUPGRADE_ALL = _hawkey.DISTUPGRADE_ALL
+DOWNGRADE = _hawkey.DOWNGRADE
+INSTALL = _hawkey.INSTALL
+UPGRADE = _hawkey.UPGRADE
+UPGRADE_ALL = _hawkey.UPGRADE_ALL
+
+ALLOW_UNINSTALL = _hawkey.ALLOW_UNINSTALL
+FORCE_BEST = _hawkey.FORCE_BEST
+VERIFY = _hawkey.VERIFY
+IGNORE_WEAK_DEPS = _hawkey.IGNORE_WEAK_DEPS
+
+PY3 = python_version.major >= 3
+
+logger = logging.getLogger('dnf')
+
+def split_nevra(s):
+ t = _hawkey.split_nevra(s)
+ return NEVRA(*t)
+
+
+class NSVCAP(_hawkey.NSVCAP):
+
+ NSVCAP_FIELDS = ["name", "stream", "version", "context", "arch", "profile"]
+
+ def _has_just_name(self):
+ return self.name and not self.stream and not self.version and \
+ not self.arch and not self.profile
+
+ def __repr__(self):
+ values = [getattr(self, i) for i in self.NSVCAP_FIELDS]
+ items = [(field, value) for field, value in zip(self.NSVCAP_FIELDS, values) if value is not None]
+ items_str = ", ".join(["{}={}".format(field, value) for field, value in items])
+ return "<NSVCAP: {}>".format(items_str)
+
+ def __eq__(self, other):
+ result = True
+ for field in self.NSVCAP_FIELDS:
+ value_self = getattr(self, field)
+ value_other = getattr(other, field)
+ result &= value_self == value_other
+ return result
+
+
+class Goal(_hawkey.Goal):
+ _goal_actions = {
+ ERASE,
+ DISTUPGRADE,
+ DISTUPGRADE_ALL,
+ DOWNGRADE,
+ INSTALL,
+ UPGRADE,
+ UPGRADE_ALL
+ }
+
+ def __init__(self, sack):
+ super(Goal, self).__init__(sack)
+ self.group_members = set()
+
+ def get_reason(self, pkg):
+ code = super(Goal, self).get_reason(pkg)
+ if code == REASON_USER and pkg.name in self.group_members:
+ return libdnf.transaction.TransactionItemReason_GROUP
+ return convert_hawkey_reason(code)
+
+ def group_reason(self, pkg, current_reason):
+ if current_reason == libdnf.transaction.TransactionItemReason_UNKNOWN and pkg.name in self.group_members:
+ return libdnf.transaction.TransactionItemReason_GROUP
+ return current_reason
+
+ def push_userinstalled(self, query, history):
+ msg = '--> Finding unneeded leftover dependencies' # translate
+ logger.debug(msg)
+
+ # get only user installed packages
+ user_installed = query.userinstalled(history.swdb)
+ self.userinstalled(user_installed)
+
+
+def _encode(obj):
+ """ Identity, except when obj is unicode then return a UTF-8 string.
+
+ This assumes UTF-8 is good enough for libsolv and always will be. Else
+ we'll have to deal with some encoding configuration.
+
+ Since we use this to match string queries, we have to enforce 'strict'
+ and potentially face exceptions rather than bizarre results. (Except
+ that as long as we stick to UTF-8 it never fails.)
+ """
+ if not PY3 and isinstance(obj, unicode):
+ return obj.encode('utf8', 'strict')
+ return obj
+
+
+def is_glob_pattern(pattern):
+ if (not PY3 and isinstance(pattern, basestring)) or \
+ (PY3 and isinstance(pattern, str)):
+ pattern = [pattern]
+ return (isinstance(pattern, list) and any(set(p) & set("*[?") for p in pattern))
+
+
+class Subject(_hawkey.Subject):
+
+ def __init__(self, pkg_spec, ignore_case=False):
+ super(Subject, self).__init__(pkg_spec, ignore_case=ignore_case)
+
+ def nsvcap_possibilities(self, *args, **kwargs):
+ poss = super(Subject, self).nsvcap_possibilities(*args, **kwargs)
+ for nsvcap in poss:
+ yield NSVCAP(nsvcap=nsvcap)
+
+ @property
+ def _filename_pattern(self):
+ return self.pattern.startswith('/') or self.pattern.startswith('*/')
+
+ def _is_arch_specified(self, solution):
+ if solution['nevra'] and solution['nevra'].arch:
+ return is_glob_pattern(solution['nevra'].arch)
+ return False
+
+ def nevra_possibilities(self, form=None):
+ warnings.simplefilter('always', DeprecationWarning)
+ msg = "The function 'nevra_possibilities' is deprecated. " \
+ "Please use 'get_nevra_possibilities' instead. The function will be removed on " \
+ "2018-01-01"
+ warnings.warn(msg, DeprecationWarning)
+ for nevra in super(Subject, self).get_nevra_possibilities(forms=form):
+ yield NEVRA(nevra=nevra)
+
+ def _get_best_selectors(self, base, forms=None, obsoletes=True, reponame=None, reports=False,
+ solution=None):
+ if solution is None:
+ solution = self.get_best_solution(base.sack, forms=forms, with_src=False)
+ q = solution['query']
+ if len(q) == 0:
+ return []
+ q = self._apply_security_filters(q, base)
+ if not q:
+ # we don't report the exact reason why any selector returned - reasons can be only src
+ # found, no package or not in requested repository. We should improve it in libdnf
+ # after movement of base.install() or base.distro_sync()
+ return []
+
+ installed_query = q.installed()
+ if not self._filename_pattern and is_glob_pattern(self.pattern) \
+ or solution['nevra'] and solution['nevra'].name is None:
+ with_obsoletes = False
+
+ if obsoletes and solution['nevra'] and solution['nevra'].has_just_name():
+ with_obsoletes = True
+ if reponame:
+ q = q.filter(reponame=reponame)
+ available_query = q.available()
+ installed_relevant_query = installed_query.filter(
+ name=[pkg.name for pkg in available_query])
+ if reports:
+ base._report_already_installed(installed_relevant_query)
+ q = available_query.union(installed_relevant_query)
+ sltrs = []
+ for name, pkgs_list in q._name_dict().items():
+ if with_obsoletes:
+ # If there is no installed package in the pkgs_list, add only
+ # obsoleters of the latest versions. Otherwise behave consistently
+ # with upgrade and add all obsoleters.
+ # See https://bugzilla.redhat.com/show_bug.cgi?id=2176263
+ # for details of the problem.
+ obsoletes_query = base.sack.query().filterm(pkg=pkgs_list)
+ if not obsoletes_query.installed():
+ obsoletes_query.filterm(latest_per_arch_by_priority=True)
+ pkgs_list = pkgs_list + base.sack.query().filter(
+ obsoletes=obsoletes_query).run()
+ sltrs.append(self._list_or_query_to_selector(base.sack, pkgs_list))
+ return sltrs
+ else:
+ if obsoletes and solution['nevra'] and solution['nevra'].has_just_name():
+ if installed_query:
+ q = q.union(base.sack.query().filter(obsoletes=q))
+ else:
+ q = q.union(base.sack.query().filter(obsoletes=q.filter(latest_per_arch_by_priority=True)))
+ installed_query = q.installed()
+
+ if reports:
+ base._report_already_installed(installed_query)
+ if reponame:
+ q = q.filter(reponame=reponame).union(installed_query)
+ if not q:
+ return []
+
+ return [self._list_or_query_to_selector(base.sack, q)]
+
+ def _apply_security_filters(self, query, base):
+ query = base._merge_update_filters(query, warning=False)
+ if not query:
+ logger.warning('No security updates for argument "{}"'.format(self.pattern)) # translate
+ return query
+
+ @staticmethod
+ def _list_or_query_to_selector(sack, list_or_query):
+ sltr = Selector(sack)
+ return sltr.set(pkg=list_or_query)
+
+
+class Repo(_hawkey.Repo):
+
+ def __init__(self, name):
+ warnings.simplefilter('always', DeprecationWarning)
+ msg = "The class hawkey.Repo is deprecated. " \
+ "Please use dnf.repo.Repo instead. The class will be removed on 2019-12-31."
+ warnings.warn(msg, DeprecationWarning)
+ super(Repo, self).__init__(name)
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+#include <datetime.h>
+
+// hawkey
+#include "dnf-advisory.h"
+#include "dnf-advisorypkg.h"
+#include "dnf-advisoryref.h"
+#include "hy-package.h"
+
+// pyhawkey
+#include "advisory-py.hpp"
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfAdvisory *advisory;
+ PyObject *sack;
+} _AdvisoryObject;
+
+
+PyObject *
+advisoryToPyObject(DnfAdvisory *advisory, PyObject *sack)
+{
+ _AdvisoryObject *self = PyObject_New(_AdvisoryObject, &advisory_Type);
+ if (!self)
+ return NULL;
+
+ self->advisory = advisory;
+ self->sack = sack;
+ Py_INCREF(sack);
+
+ return (PyObject *)self;
+}
+
+static DnfAdvisory *
+advisoryFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &advisory_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected an Advisory object.");
+ return NULL;
+ }
+ return ((_AdvisoryObject*)o)->advisory;
+}
+
+static int
+advisory_converter(PyObject *o, DnfAdvisory **advisory_ptr)
+{
+ DnfAdvisory *advisory = advisoryFromPyObject(o);
+ if (advisory == NULL)
+ return 0;
+ *advisory_ptr = advisory;
+ return 1;
+}
+
+/* functions on the type */
+
+static void
+advisory_dealloc(_AdvisoryObject *self)
+{
+ dnf_advisory_free(self->advisory);
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+advisory_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *result;
+ DnfAdvisory *cself, *cother;
+
+ if (!advisory_converter(self, &cself) ||
+ !advisory_converter(other, &cother)) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ int identical = dnf_advisory_compare(cself, cother);
+ switch (op) {
+ case Py_EQ:
+ result = TEST_COND(identical);
+ break;
+ case Py_NE:
+ result = TEST_COND(!identical);
+ break;
+ case Py_LE:
+ case Py_GE:
+ case Py_LT:
+ case Py_GT:
+ result = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+} CATCH_TO_PYTHON
+
+/* getsetters */
+
+static PyObject *
+get_str(_AdvisoryObject *self, void *closure) try
+{
+ const char *(*func)(DnfAdvisory*);
+ const char *cstr;
+
+ func = (const char *(*)(DnfAdvisory*))closure;
+ cstr = func(self->advisory);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_type(_AdvisoryObject *self, void *closure) try
+{
+ DnfAdvisoryKind (*func)(DnfAdvisory*);
+ DnfAdvisoryKind ctype;
+
+ func = (DnfAdvisoryKind (*)(DnfAdvisory*))closure;
+ ctype = func(self->advisory);
+ return PyLong_FromLong(ctype);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_datetime(_AdvisoryObject *self, void *closure) try
+{
+ guint64 (*func)(DnfAdvisory*);
+ func = (guint64 (*)(DnfAdvisory*))closure;
+ UniquePtrPyObject timestamp(PyLong_FromUnsignedLongLong(func(self->advisory)));
+ UniquePtrPyObject args(Py_BuildValue("(O)", timestamp.get()));
+ PyDateTime_IMPORT;
+ PyObject *datetime = PyDateTime_FromTimestamp(args.get());
+ return datetime;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_advisorypkg_list(_AdvisoryObject *self, void *closure) try
+{
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+ self->advisory->getPackages(advisoryPkgs);
+ return advisoryPkgVectorToPylist(advisoryPkgs);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_advisoryref_list(_AdvisoryObject *self, void *closure) try
+{
+ std::vector<libdnf::AdvisoryRef> advisoryRefs;
+ self->advisory->getReferences(advisoryRefs);
+ return advisoryRefVectorToPylist(advisoryRefs, self->sack);
+} CATCH_TO_PYTHON
+
+static PyObject *
+matchBugOrCVE(_AdvisoryObject *self, PyObject *args, bool bug)
+{
+ PyObject *string;
+ if (!PyArg_ParseTuple(args, "O", &string))
+ return NULL;
+
+ PycompString cmatch(string);
+ if (!cmatch.getCString())
+ return NULL;
+
+ bool retValue;
+ if (bug) {
+ retValue = self->advisory->matchBug(cmatch.getCString());
+ } else {
+ retValue = self->advisory->matchCVE(cmatch.getCString());
+ }
+ return PyBool_FromLong(retValue);
+}
+
+static PyObject *
+matchBug(_AdvisoryObject *self, PyObject *args) try
+{
+ return matchBugOrCVE(self, args, true);
+} CATCH_TO_PYTHON
+
+static PyObject *
+matchCVE(_AdvisoryObject *self, PyObject *args) try
+{
+ return matchBugOrCVE(self, args, false);
+} CATCH_TO_PYTHON
+
+static PyGetSetDef advisory_getsetters[] = {
+ {(char*)"title", (getter)get_str, NULL, NULL, (void *)dnf_advisory_get_title},
+ {(char*)"id", (getter)get_str, NULL, NULL, (void *)dnf_advisory_get_id},
+ {(char*)"type", (getter)get_type, NULL, NULL, (void *)dnf_advisory_get_kind},
+ {(char*)"description", (getter)get_str, NULL, NULL, (void *)dnf_advisory_get_description},
+ {(char*)"rights", (getter)get_str, NULL, NULL, (void *)dnf_advisory_get_rights},
+ {(char*)"severity", (getter)get_str, NULL, NULL, (void *)dnf_advisory_get_severity},
+ {(char*)"updated", (getter)get_datetime, NULL, NULL, (void *)dnf_advisory_get_updated},
+ {(char*)"packages", (getter)get_advisorypkg_list, NULL, NULL, NULL},
+ {(char*)"references", (getter)get_advisoryref_list, NULL, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+static struct PyMethodDef advisory_methods[] = {
+ {"match_bug", (PyCFunction)matchBug, METH_VARARGS, NULL},
+ {"match_cve", (PyCFunction)matchCVE, METH_VARARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject advisory_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Advisory", /*tp_name*/
+ sizeof(_AdvisoryObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) advisory_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Advisory object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ advisory_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ advisory_methods, /* tp_methods */
+ 0, /* tp_members */
+ advisory_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ADVISORY_PY_H
+#define ADVISORY_PY_H
+
+extern PyTypeObject advisory_Type;
+
+PyObject * advisoryToPyObject(DnfAdvisory *advisory, PyObject *sack);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// hawkey
+#include "dnf-advisorypkg.h"
+#include "sack/advisorypkg.hpp"
+
+// pyhawkey
+#include "advisorypkg-py.hpp"
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+
+#include "pycomp.hpp"
+#include "sack-py.hpp"
+#include "advisory-py.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfAdvisoryPkg *advisorypkg;
+} _AdvisoryPkgObject;
+
+
+PyObject *
+advisorypkgToPyObject(DnfAdvisoryPkg *advisorypkg)
+{
+ _AdvisoryPkgObject *self = PyObject_New(_AdvisoryPkgObject, &advisorypkg_Type);
+ if (!self)
+ return NULL;
+ self->advisorypkg = advisorypkg;
+ return (PyObject *)self;
+}
+
+static DnfAdvisoryPkg *
+advisorypkgFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &advisorypkg_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected an AdvisoryPkg object.");
+ return NULL;
+ }
+ return ((_AdvisoryPkgObject*)o)->advisorypkg;
+}
+
+static int
+advisorypkg_converter(PyObject *o, DnfAdvisoryPkg **ref_ptr)
+{
+ DnfAdvisoryPkg *ref = advisorypkgFromPyObject(o);
+ if (ref == NULL)
+ return 0;
+ *ref_ptr = ref;
+ return 1;
+}
+
+/* functions on the type */
+
+static void
+advisorypkg_dealloc(_AdvisoryPkgObject *self)
+{
+ dnf_advisorypkg_free(self->advisorypkg);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+advisorypkg_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *result;
+ DnfAdvisoryPkg *cself, *cother;
+
+ if (!advisorypkg_converter(self, &cself) ||
+ !advisorypkg_converter(other, &cother)) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ int identical = dnf_advisorypkg_compare(cself, cother);
+ switch (op) {
+ case Py_EQ:
+ result = TEST_COND(identical);
+ break;
+ case Py_NE:
+ result = TEST_COND(!identical);
+ break;
+ case Py_LE:
+ case Py_GE:
+ case Py_LT:
+ case Py_GT:
+ result = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+} CATCH_TO_PYTHON
+
+/* getsetters */
+
+static PyObject *
+get_attr(_AdvisoryPkgObject *self, void *closure) try
+{
+ intptr_t str_key = (intptr_t)closure;
+ if (str_key == 0)
+ return PyUnicode_FromString(dnf_advisorypkg_get_name(self->advisorypkg));
+ if (str_key == 1)
+ return PyUnicode_FromString(dnf_advisorypkg_get_evr(self->advisorypkg));
+ if (str_key == 2)
+ return PyUnicode_FromString(dnf_advisorypkg_get_arch(self->advisorypkg));
+ if (str_key == 3)
+ return PyUnicode_FromString(dnf_advisorypkg_get_filename(self->advisorypkg));
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_advisory(_AdvisoryPkgObject *self, PyObject *args) try
+{
+ PyObject *sack = NULL;
+ if (!PyArg_ParseTuple(args, "O!", &sack_Type, &sack))
+ return NULL;
+ auto advisory = self->advisorypkg->getAdvisory();
+ return advisoryToPyObject(advisory, sack);
+} CATCH_TO_PYTHON
+
+static struct PyMethodDef advisorypkg_methods[] = {
+ {"get_advisory", (PyCFunction)get_advisory, METH_VARARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+static PyGetSetDef advisorypkg_getsetters[] = {
+ {(char*)"name", (getter)get_attr, NULL, NULL, (void *)0},
+ {(char*)"evr", (getter)get_attr, NULL, NULL, (void *)1},
+ {(char*)"arch", (getter)get_attr, NULL, NULL, (void *)2},
+ {(char*)"filename", (getter)get_attr, NULL, NULL, (void *)3},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject advisorypkg_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.AdvisoryPkg", /*tp_name*/
+ sizeof(_AdvisoryPkgObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) advisorypkg_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "AdvisoryPkg object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ advisorypkg_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ advisorypkg_methods, /* tp_methods */
+ 0, /* tp_members */
+ advisorypkg_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ADVISORYPKG_PY_H
+#define ADVISORYPKG_PY_H
+
+// hawkey
+#include "hy-types.h"
+
+extern PyTypeObject advisorypkg_Type;
+
+PyObject *advisorypkgToPyObject(DnfAdvisoryPkg *advisorypkg);
+
+#endif // ADVISORYPKG_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// hawkey
+#include "dnf-advisoryref.h"
+
+// pyhawkey
+#include "advisoryref-py.hpp"
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfAdvisoryRef *advisoryref;
+ PyObject *sack;
+} _AdvisoryRefObject;
+
+
+PyObject *
+advisoryrefToPyObject(DnfAdvisoryRef *advisoryref, PyObject *sack)
+{
+ _AdvisoryRefObject *self = PyObject_New(_AdvisoryRefObject, &advisoryref_Type);
+ if (!self)
+ return NULL;
+
+ self->advisoryref = advisoryref;
+ self->sack = sack;
+ Py_INCREF(sack);
+
+ return (PyObject *)self;
+}
+
+static DnfAdvisoryRef *
+advisoryrefFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &advisoryref_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected an AdvisoryRef object.");
+ return NULL;
+ }
+ return ((_AdvisoryRefObject*)o)->advisoryref;
+}
+
+static int
+advisoryref_converter(PyObject *o, DnfAdvisoryRef **ref_ptr)
+{
+ DnfAdvisoryRef *ref = advisoryrefFromPyObject(o);
+ if (ref == NULL)
+ return 0;
+ *ref_ptr = ref;
+ return 1;
+}
+
+/* functions on the type */
+
+static void
+advisoryref_dealloc(_AdvisoryRefObject *self)
+{
+ dnf_advisoryref_free(self->advisoryref);
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+advisoryref_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *result;
+ DnfAdvisoryRef *cself, *cother;
+
+ if (!advisoryref_converter(self, &cself) ||
+ !advisoryref_converter(other, &cother)) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ int identical = dnf_advisoryref_compare(cself, cother);
+ switch (op) {
+ case Py_EQ:
+ result = TEST_COND(identical);
+ break;
+ case Py_NE:
+ result = TEST_COND(!identical);
+ break;
+ case Py_LE:
+ case Py_GE:
+ case Py_LT:
+ case Py_GT:
+ result = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+} CATCH_TO_PYTHON
+
+/* getsetters */
+
+static PyObject *
+get_type(_AdvisoryRefObject *self, void *closure) try
+{
+ DnfAdvisoryRefKind (*func)(DnfAdvisoryRef*);
+ DnfAdvisoryRefKind ctype;
+
+ func = (DnfAdvisoryRefKind (*)(DnfAdvisoryRef*))closure;
+ ctype = func(self->advisoryref);
+ return PyLong_FromLong(ctype);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_str(_AdvisoryRefObject *self, void *closure) try
+{
+ const char *(*func)(DnfAdvisoryRef*);
+ const char *cstr;
+
+ func = (const char *(*)(DnfAdvisoryRef*))closure;
+ cstr = func(self->advisoryref);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static PyGetSetDef advisoryref_getsetters[] = {
+ {(char*)"type", (getter)get_type, NULL, NULL, (void *)dnf_advisoryref_get_kind},
+ {(char*)"id", (getter)get_str, NULL, NULL, (void *)dnf_advisoryref_get_id},
+ {(char*)"title", (getter)get_str, NULL, NULL, (void *)dnf_advisoryref_get_title},
+ {(char*)"url", (getter)get_str, NULL, NULL, (void *)dnf_advisoryref_get_url},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject advisoryref_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.AdvisoryRef", /*tp_name*/
+ sizeof(_AdvisoryRefObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) advisoryref_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "AdvisoryRef object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ advisoryref_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ advisoryref_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ADVISORYREF_PY_H
+#define ADVISORYREF_PY_H
+
+// hawkey
+#include "hy-types.h"
+
+extern PyTypeObject advisoryref_Type;
+
+PyObject *advisoryrefToPyObject(DnfAdvisoryRef *advisoryref, PyObject *sack);
+
+#endif // ADVISORYREF_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// hawkey
+#include "dnf-types.h"
+
+// pyhawkey
+#include "exception-py.hpp"
+
+PyObject *HyExc_Exception = NULL;
+PyObject *HyExc_Value = NULL;
+PyObject *HyExc_Query = NULL;
+PyObject *HyExc_Arch = NULL;
+PyObject *HyExc_Runtime = NULL;
+PyObject *HyExc_Validation = NULL;
+
+int
+init_exceptions(void)
+{
+ HyExc_Exception = PyErr_NewException((char*) "_hawkey.Exception", NULL, NULL);
+ if (!HyExc_Exception)
+ return 0;
+
+ HyExc_Value = PyErr_NewException((char*) "_hawkey.ValueException", HyExc_Exception,
+ NULL);
+ if (!HyExc_Value)
+ return 0;
+
+ HyExc_Query = PyErr_NewException((char*) "_hawkey.QueryException", HyExc_Value,
+ NULL);
+ if (!HyExc_Query)
+ return 0;
+
+ HyExc_Arch = PyErr_NewException((char*) "_hawkey.ArchException", HyExc_Value,
+ NULL);
+ if (!HyExc_Arch)
+ return 0;
+
+ HyExc_Runtime = PyErr_NewException((char*) "_hawkey.RuntimeException",
+ HyExc_Exception, NULL);
+ if (!HyExc_Runtime)
+ return 0;
+
+ HyExc_Validation = PyErr_NewException((char*) "_hawkey.ValidationException",
+ HyExc_Exception, NULL);
+ if (!HyExc_Validation)
+ return 0;
+
+ return 1;
+}
+
+int
+ret2e(int ret, const char *msg)
+{
+ PyObject *exctype = NULL;
+ switch (ret) {
+ case 0:
+ return 0;
+ case DNF_ERROR_FAILED:
+ exctype = HyExc_Runtime;
+ break;
+ case DNF_ERROR_FILE_INVALID: {
+ exctype = PyExc_IOError;
+ break;
+ }
+ case DNF_ERROR_INTERNAL_ERROR:
+ case DNF_ERROR_BAD_SELECTOR:
+ exctype = HyExc_Value;
+ break;
+ default:
+ // try to end it quickly
+ assert(0);
+ // or fallback to an internal-error exception
+ PyErr_SetString(PyExc_AssertionError, msg);
+ return 1;
+ }
+
+ assert(exctype);
+ PyErr_SetString(exctype, msg);
+ return 1;
+}
+
+
+PyObject *
+op_error2exc(const GError *error)
+{
+ if (error == NULL)
+ Py_RETURN_NONE;
+
+ switch (error->code) {
+ case DNF_ERROR_BAD_SELECTOR:
+ PyErr_SetString(HyExc_Value,
+ "Ill-formed Selector used for the operation.");
+ return NULL;
+ case DNF_ERROR_INVALID_ARCHITECTURE:
+ PyErr_SetString(HyExc_Arch, "Used arch is unknown.");
+ return NULL;
+ case DNF_ERROR_PACKAGE_NOT_FOUND:
+ PyErr_SetString(HyExc_Validation, "The validation check has failed.");
+ return NULL;
+ case DNF_ERROR_FILE_INVALID:
+ PyErr_SetString(PyExc_IOError, error->message);
+ return NULL;
+ case DNF_ERROR_CANNOT_WRITE_CACHE:
+ PyErr_SetString(PyExc_IOError, "Failed writing the cache.");
+ return NULL;
+ default:
+ PyErr_SetString(HyExc_Exception, error->message);
+ return NULL;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EXCEPTION_PY_H
+#define EXCEPTION_PY_H
+
+#include "error.hpp"
+
+#include <glib.h>
+
+extern PyObject *HyExc_Exception;
+extern PyObject *HyExc_Value;
+extern PyObject *HyExc_Query;
+extern PyObject *HyExc_Arch;
+extern PyObject *HyExc_Runtime;
+extern PyObject *HyExc_Validation;
+
+int init_exceptions(void);
+PyObject *op_error2exc(const GError *error);
+int ret2e(int ret, const char *msg);
+
+#define CATCH_TO_PYTHON_RET(RET) catch (const libdnf::Error& e) { \
+ PyErr_Format(HyExc_Exception, e.what()); \
+ return RET; \
+}
+
+#define CATCH_TO_PYTHON CATCH_TO_PYTHON_RET(NULL)
+#define CATCH_TO_PYTHON_INT CATCH_TO_PYTHON_RET(-1)
+
+#endif // EXCEPTION_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+#include <glib.h>
+#include <structmember.h>
+#include <stddef.h>
+#include <solv/util.h>
+
+#include "dnf-types.h"
+#include "dnf-goal.h"
+
+#include "exception-py.hpp"
+#include "goal-py.hpp"
+#include "hy-goal-private.hpp"
+#include "iutil-py.hpp"
+#include "package-py.hpp"
+#include "selector-py.hpp"
+#include "sack-py.hpp"
+#include "query-py.hpp"
+#include "pycomp.hpp"
+#include "goal/Goal.hpp"
+#include "sack/query.hpp"
+#include "sack/packageset.hpp"
+
+#define BLOCK_SIZE 15
+
+typedef struct {
+ PyObject_HEAD
+ HyGoal goal;
+ PyObject *sack;
+} _GoalObject;
+
+static int
+args_pkg_sltr_check(DnfPackage *pkg, HySelector sltr)
+{
+ if (!(pkg || sltr)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Requires a Package or a Selector argument.");
+ return 0;
+ }
+ if (pkg && sltr) {
+ PyErr_SetString(PyExc_ValueError,
+ "Does not accept both Package and Selector arguments.");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+args_pkg_sltr_parse(PyObject *args, PyObject *kwds,
+ DnfPackage **pkg, HySelector *sltr, int *flags, int flag_mask)
+{
+ const char *kwlist[] = {"package", "select", "clean_deps", "check_installed",
+ "optional", NULL};
+ int clean_deps = 0, check_installed = 0, optional = 0;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O&iii", (char**) kwlist,
+ package_converter, pkg,
+ selector_converter, sltr,
+ &clean_deps, &check_installed,
+ &optional))
+ return 0;
+ if (!args_pkg_sltr_check(*pkg, *sltr))
+ return 0;
+ if (clean_deps) {
+ if (!(flag_mask & HY_CLEAN_DEPS)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Does not accept clean_deps keyword") ;
+ return 0;
+ }
+ *flags |= HY_CLEAN_DEPS;
+ }
+ if (check_installed) {
+ if (!(flag_mask & HY_CHECK_INSTALLED)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Does not accept check_installed keyword") ;
+ return 0;
+ }
+ *flags |= HY_CHECK_INSTALLED;
+ }
+ if (optional) {
+ if (!(flag_mask & HY_WEAK_SOLV)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Does not accept optional keyword");
+ return 0;
+ }
+ *flags |= HY_WEAK_SOLV;
+ }
+ return 1;
+}
+
+static int
+args_run_parse(PyObject *args, PyObject *kwds, int *flags, PyObject **callback_p)
+{
+ const char *kwlist[] = {"callback", "allow_uninstall", "force_best", "verify",
+ "ignore_weak_deps", "ignore_weak", NULL};
+ int ignore_weak = 0;
+ int ignore_weak_deps = 0;
+ int allow_uninstall = 0;
+ int force_best = 0;
+ int verify = 0;
+ PyObject *callback = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oiiiii", (char**) kwlist,
+ &callback, &allow_uninstall, &force_best,
+ &verify, &ignore_weak_deps, &ignore_weak))
+ return 0;
+
+ if (callback) {
+ if (!callback_p) {
+ PyErr_SetString(PyExc_ValueError,
+ "Does not accept a callback argument.");
+ return 0;
+ }
+ if (!PyCallable_Check(callback)) {
+ PyErr_SetString(PyExc_ValueError, "Must be a callable object.");
+ return 0;
+ }
+ *callback_p = callback;
+ } else if (callback_p) {
+ PyErr_SetString(PyExc_ValueError, "Expected a callback argument.");
+ return 0;
+ }
+
+ if (allow_uninstall)
+ *flags |= DNF_ALLOW_UNINSTALL;
+ if (force_best)
+ *flags |= DNF_FORCE_BEST;
+ if (verify)
+ *flags |= DNF_VERIFY;
+ if (ignore_weak_deps)
+ *flags |= DNF_IGNORE_WEAK_DEPS;
+ if (ignore_weak)
+ *flags |= DNF_IGNORE_WEAK;
+ return 1;
+}
+
+static PyObject *
+op_ret2exc(int ret)
+{
+ if (!ret)
+ Py_RETURN_NONE;
+
+ switch (ret) {
+ case DNF_ERROR_BAD_SELECTOR:
+ PyErr_SetString(HyExc_Value,
+ "Ill-formed Selector used for the operation.");
+ return NULL;
+ case DNF_ERROR_INVALID_ARCHITECTURE:
+ PyErr_SetString(HyExc_Arch, "Used arch is unknown.");
+ return NULL;
+ case DNF_ERROR_PACKAGE_NOT_FOUND:
+ PyErr_SetString(HyExc_Validation, "The validation check has failed.");
+ return NULL;
+ default:
+ PyErr_SetString(HyExc_Exception, "Goal operation failed.");
+ return NULL;
+ }
+}
+
+/* functions on the type */
+
+static PyObject *
+goal_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _GoalObject *self = (_GoalObject*)type->tp_alloc(type, 0);
+ if (self) {
+ self->goal = NULL;
+ self->sack = NULL;
+ }
+ return (PyObject*)self;
+} CATCH_TO_PYTHON
+
+static void
+goal_dealloc(_GoalObject *self)
+{
+ if (self->goal)
+ hy_goal_free(self->goal);
+
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+goal_init(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ PyObject *sack;
+ DnfSack *csack;
+
+ if (!PyArg_ParseTuple(args, "O!", &sack_Type, &sack))
+ return -1;
+ csack = sackFromPyObject(sack);
+ if (csack == NULL)
+ return -1;
+ self->sack = sack;
+ Py_INCREF(self->sack); // sack has to kept around until we are
+ self->goal = hy_goal_create(csack);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+/* object methods */
+
+static PyObject *
+distupgrade_all(_GoalObject *self, PyObject *unused) try
+{
+ int ret = hy_goal_distupgrade_all(self->goal);
+ return op_ret2exc(ret);
+} CATCH_TO_PYTHON
+
+static PyObject *
+distupgrade(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ DnfPackage *pkg = NULL;
+ HySelector sltr = NULL;
+ if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0))
+ return NULL;
+
+ int ret = pkg ? hy_goal_distupgrade(self->goal, pkg) :
+ hy_goal_distupgrade_selector(self->goal, sltr);
+ return op_ret2exc(ret);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_protect_running_kernel(_GoalObject *self, void * unused) try
+{
+ return PyBool_FromLong(self->goal->get_protect_running_kernel());
+} CATCH_TO_PYTHON
+
+static int
+set_protect_running_kernel(_GoalObject *self, PyObject * value, void * closure) try
+{
+ if(!PyBool_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "Only Bool Type accepted");
+ return -1;
+ }
+ int c_value = PyObject_IsTrue(value);
+ self->goal->set_protect_running_kernel(c_value);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+erase(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ DnfPackage *pkg = NULL;
+ HySelector sltr = NULL;
+ int flags = 0;
+ if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_CLEAN_DEPS))
+ return NULL;
+
+ int ret = pkg ? hy_goal_erase_flags(self->goal, pkg, flags) :
+ hy_goal_erase_selector_flags(self->goal, sltr, flags);
+ return op_ret2exc(ret);
+} CATCH_TO_PYTHON
+
+static PyObject *
+install(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ DnfPackage *pkg = NULL;
+ HySelector sltr = NULL;
+ int flags = 0;
+ g_autoptr(GError) error = NULL;
+ if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, &flags, HY_WEAK_SOLV))
+ return NULL;
+
+ if (flags & HY_WEAK_SOLV) {
+ if (pkg) {
+ hy_goal_install_optional(self->goal, pkg);
+ } else {
+ hy_goal_install_selector_optional(self->goal, sltr, &error);
+ }
+ } else {
+ if (pkg) {
+ hy_goal_install(self->goal, pkg);
+ } else {
+ hy_goal_install_selector(self->goal, sltr, &error);
+ }
+ }
+ return op_error2exc(error);
+} CATCH_TO_PYTHON
+
+static PyObject *
+upgrade(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ DnfPackage *pkg = NULL;
+ HySelector sltr = NULL;
+
+ if (!args_pkg_sltr_parse(args, kwds, &pkg, &sltr, NULL, 0))
+ return NULL;
+ if (pkg) {
+ int ret = hy_goal_upgrade_to(self->goal, pkg);
+ return op_ret2exc(ret);
+ }
+ int ret = hy_goal_upgrade_selector(self->goal, sltr);
+ return op_ret2exc(ret);
+} CATCH_TO_PYTHON
+
+static PyObject *
+upgrade_all(_GoalObject *self, PyObject *unused) try
+{
+ int ret = hy_goal_upgrade_all(self->goal);
+ return op_ret2exc(ret);
+} CATCH_TO_PYTHON
+
+static PyObject *
+userinstalled(_GoalObject *self, PyObject *obj) try
+{
+ if (queryObject_Check(obj)) {
+ HyQuery query = queryFromPyObject(obj);
+ if (query == NULL)
+ return NULL;
+ self->goal->userInstalled(*query->getResultPset());
+ Py_RETURN_FALSE;
+ }
+ DnfPackage *cpkg = packageFromPyObject(obj);
+ int ret;
+
+ if (cpkg == NULL)
+ return NULL;
+ ret = hy_goal_userinstalled(self->goal, cpkg);
+ if (!ret)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_actions(_GoalObject *self, void *unused) try
+{
+ HyGoal goal = self->goal;
+ return PyLong_FromLong(goal->getActions());
+} CATCH_TO_PYTHON
+
+static PyObject *
+req_has_distupgrade_all(_GoalObject *self, PyObject *unused) try
+{
+ return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_DISTUPGRADE_ALL));
+} CATCH_TO_PYTHON
+
+static PyObject *
+req_has_erase(_GoalObject *self, PyObject *unused) try
+{
+ return PyBool_FromLong(hy_goal_has_actions(self->goal, DNF_ERASE));
+} CATCH_TO_PYTHON
+
+static PyObject *
+req_length(_GoalObject *self, PyObject *unused) try
+{
+ return PyLong_FromLong(hy_goal_req_length(self->goal));
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_protected(_GoalObject *self, PyObject *seq) try
+{
+ HyGoal goal = self->goal;
+ auto pset = pyseq_to_packageset(seq, hy_goal_get_sack(goal));
+ if (!pset)
+ return NULL;
+ dnf_goal_add_protected(goal, pset.get());
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_exclude_from_weak(_GoalObject *self, PyObject *seq) try
+{
+ HyGoal goal = self->goal;
+ auto pset = pyseq_to_packageset(seq, hy_goal_get_sack(goal));
+ if (!pset)
+ return NULL;
+ goal->add_exclude_from_weak(*(pset.get()));
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+reset_exclude_from_weak(_GoalObject *self, PyObject *unused) try
+{
+ HyGoal goal = self->goal;
+ goal->reset_exclude_from_weak();
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+exclude_from_weak_autodetect(_GoalObject *self, PyObject *unused) try
+{
+ HyGoal goal = self->goal;
+ goal->exclude_from_weak_autodetect();
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+run(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ int flags = 0;
+ if (!args_run_parse(args, kwds, &flags, NULL))
+ return NULL;
+
+ int ret = hy_goal_run_flags(self->goal, static_cast<DnfGoalActions>(flags));
+ if (!ret)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+count_problems(_GoalObject *self, PyObject *unused) try
+{
+ return PyLong_FromLong(hy_goal_count_problems(self->goal));
+} CATCH_TO_PYTHON
+
+/**
+ * Reports problems described in strings.
+ *
+ * Returns Python list with Python list of strings for each problem or empty Python list if no
+ * problem or NULL in case of error.
+ */
+static PyObject *
+problem_rules(_GoalObject *self, PyObject *unused) try
+{
+ auto allProblems = self->goal->describeAllProblemRules(true);
+ return problemRulesPyConverter(allProblems);
+} CATCH_TO_PYTHON
+
+/**
+ * Reports packages that has a conflict
+ *
+ * Returns Python list with package objects that have a conflict.
+ */
+static PyObject *
+problem_conflicts(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"available", NULL};
+ int available = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available))
+ return 0;
+
+ DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL;
+ if (available)
+ pkg_type = DNF_PACKAGE_STATE_AVAILABLE;
+ auto pset = self->goal->listConflictPkgs(pkg_type);
+ return packageset_to_pylist(pset.get(), self->sack);
+} CATCH_TO_PYTHON
+
+/**
+ * Reports packages that has a conflict
+ *
+ * Returns Python list with package objects that have a conflict.
+ */
+static PyObject *
+problem_broken_dependency(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"available", NULL};
+ int available = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", (char**) kwlist, &available))
+ return 0;
+
+ DnfPackageState pkg_type = DNF_PACKAGE_STATE_ALL;
+
+ if (available)
+ pkg_type = DNF_PACKAGE_STATE_AVAILABLE;
+ auto pset = self->goal->listBrokenDependencyPkgs(pkg_type);
+
+ return packageset_to_pylist(pset.get(), self->sack);
+} CATCH_TO_PYTHON
+
+static PyObject *
+file_dep_problem_present(_GoalObject *self, PyObject *unused) try
+{
+ return PyBool_FromLong(self->goal->isBrokenFileDependencyPresent());
+} CATCH_TO_PYTHON
+
+static PyObject *
+log_decisions(_GoalObject *self, PyObject *unused) try
+{
+ if (hy_goal_log_decisions(self->goal))
+ PyErr_SetString(PyExc_ValueError, "log_decisions() failed.");
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+write_debugdata(_GoalObject *self, PyObject *dir_str) try
+{
+ g_autoptr(GError) error = NULL;
+ PycompString dir(dir_str);
+
+ if (!dir.getCString())
+ return NULL;
+
+ gboolean ret = hy_goal_write_debugdata(self->goal, dir.getCString(), &error);
+ if (!ret) {
+ op_error2exc(error);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_generic(_GoalObject *self, GPtrArray *(*func)(HyGoal, GError **))
+{
+ g_autoptr(GError) error = NULL;
+ GPtrArray *plist = func(self->goal, &error);
+ PyObject *list;
+
+ if (!plist) {
+ switch (error->code) {
+ case DNF_ERROR_INTERNAL_ERROR:
+ PyErr_SetString(HyExc_Value, "Goal has not been run yet.");
+ break;
+ case DNF_ERROR_NO_SOLUTION:
+ PyErr_SetString(HyExc_Runtime, "Goal could not find a solution.");
+ break;
+ default:
+ assert(0);
+ }
+ return NULL;
+ }
+ list = packagelist_to_pylist(plist, self->sack);
+ g_ptr_array_unref(plist);
+ return list;
+}
+
+static PyObject *
+list_erasures(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_erasures);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_installs(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_installs);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_obsoleted(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_obsoleted);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_reinstalls(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_reinstalls);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_unneeded(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_unneeded);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_suggested(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_suggested);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_downgrades(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_downgrades);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_upgrades(_GoalObject *self, PyObject *unused) try
+{
+ return list_generic(self, hy_goal_list_upgrades);
+} CATCH_TO_PYTHON
+
+static PyObject *
+obsoleted_by_package(_GoalObject *self, PyObject *pkg) try
+{
+ DnfPackage *cpkg = packageFromPyObject(pkg);
+
+ if (cpkg == NULL)
+ return NULL;
+ GPtrArray *plist = hy_goal_list_obsoleted_by_package(self->goal, cpkg);
+ PyObject *list = packagelist_to_pylist(plist, self->sack);
+ g_ptr_array_unref(plist);
+ return list;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_reason(_GoalObject *self, PyObject *pkg) try
+{
+ DnfPackage *cpkg = packageFromPyObject(pkg);
+
+ if (cpkg == NULL)
+ return NULL;
+ int reason = hy_goal_get_reason(self->goal, cpkg);
+ return PyLong_FromLong(reason);
+} CATCH_TO_PYTHON
+
+static PyObject *
+goalToPyObject(HyGoal goal, PyObject *sack)
+{
+ _GoalObject *self = (_GoalObject *)goal_Type.tp_alloc(&goal_Type, 0);
+ if (self) {
+ self->goal = goal;
+ self->sack = sack;
+ Py_INCREF(sack);
+ }
+ return (PyObject *)self;
+}
+
+static PyObject *
+deepcopy(_GoalObject *self, PyObject *args, PyObject *kwds) try
+{
+ HyGoal goal = hy_goal_clone(self->goal);
+ return goalToPyObject(goal, self->sack);
+} CATCH_TO_PYTHON
+
+static struct PyMethodDef goal_methods[] = {
+ {"__deepcopy__", (PyCFunction)deepcopy, METH_KEYWORDS|METH_VARARGS,
+ NULL},
+ {"add_protected", (PyCFunction)add_protected, METH_O,
+ NULL},
+ {"add_exclude_from_weak", (PyCFunction)add_exclude_from_weak, METH_O, NULL},
+ {"reset_exclude_from_weak", (PyCFunction)reset_exclude_from_weak, METH_NOARGS, NULL},
+ {"exclude_from_weak_autodetect", (PyCFunction)exclude_from_weak_autodetect, METH_NOARGS, NULL},
+ {"distupgrade_all", (PyCFunction)distupgrade_all, METH_NOARGS, NULL},
+ {"distupgrade", (PyCFunction)distupgrade,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"erase", (PyCFunction)erase,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"install", (PyCFunction)install,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"upgrade", (PyCFunction)upgrade,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"upgrade_all", (PyCFunction)upgrade_all, METH_NOARGS, NULL},
+ {"userinstalled", (PyCFunction)userinstalled, METH_O, NULL},
+ // deprecated in 0.5.9, will be removed in 1.0.0
+ // use goal.actions & hawkey.DISTUPGRADE_ALL instead
+ {"req_has_distupgrade_all", (PyCFunction)req_has_distupgrade_all,
+ METH_NOARGS, NULL},
+ // deprecated in 0.5.9, will be removed in 1.0.0
+ // use goal.actions | hawkey.ERASE instead
+ {"req_has_erase", (PyCFunction)req_has_erase, METH_NOARGS, NULL},
+ {"req_length", (PyCFunction)req_length, METH_NOARGS, NULL},
+ {"run", (PyCFunction)run,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"count_problems", (PyCFunction)count_problems, METH_NOARGS, NULL},
+ {"problem_conflicts",(PyCFunction)problem_conflicts, METH_VARARGS | METH_KEYWORDS, NULL},
+ {"problem_broken_dependency",(PyCFunction)problem_broken_dependency, METH_VARARGS | METH_KEYWORDS, NULL},
+ {"problem_rules", (PyCFunction)problem_rules, METH_NOARGS, NULL},
+ {"file_dep_problem_present", (PyCFunction)file_dep_problem_present, METH_NOARGS, NULL},
+ {"log_decisions", (PyCFunction)log_decisions, METH_NOARGS, NULL},
+ {"write_debugdata", (PyCFunction)write_debugdata, METH_O, NULL},
+ {"list_erasures", (PyCFunction)list_erasures, METH_NOARGS, NULL},
+ {"list_installs", (PyCFunction)list_installs, METH_NOARGS, NULL},
+ {"list_obsoleted", (PyCFunction)list_obsoleted, METH_NOARGS, NULL},
+ {"list_reinstalls", (PyCFunction)list_reinstalls, METH_NOARGS, NULL},
+ {"list_unneeded", (PyCFunction)list_unneeded, METH_NOARGS, NULL},
+ {"list_suggested", (PyCFunction)list_suggested, METH_NOARGS, NULL},
+ {"list_downgrades", (PyCFunction)list_downgrades, METH_NOARGS, NULL},
+ {"list_upgrades", (PyCFunction)list_upgrades, METH_NOARGS, NULL},
+ {"obsoleted_by_package",(PyCFunction)obsoleted_by_package,
+ METH_O, NULL},
+ {"get_reason", (PyCFunction)get_reason, METH_O, NULL},
+ {NULL} /* sentinel */
+};
+
+static struct PyMemberDef goal_members[] = {
+ {(char*)"sack", T_OBJECT, offsetof(_GoalObject, sack), READONLY, NULL},
+ {NULL}
+};
+
+static PyGetSetDef goal_getsetters[] = {
+ {(char*)"actions", (getter)get_actions, NULL, NULL, NULL},
+ {(char*)"protect_running_kernel", (getter)get_protect_running_kernel,
+ (setter)set_protect_running_kernel, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject goal_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Goal", /*tp_name*/
+ sizeof(_GoalObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) goal_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ PyObject_GenericGetAttr, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Goal object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ 0, /* tp_iternext */
+ goal_methods, /* tp_methods */
+ goal_members, /* tp_members */
+ goal_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)goal_init, /* tp_init */
+ 0, /* tp_alloc */
+ goal_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GOAL_PY_H
+#define GOAL_PY_H
+
+extern PyTypeObject goal_Type;
+
+#endif
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef HAWKEY_PYSYS_H
+#define HAWKEY_PYSYS_H
+
+#ifndef Py_TYPE
+#define Py_TYPE(o) ((o)->ob_type)
+#endif
+
+#endif // HAWKEY_PYSYS_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+#include <libintl.h>
+
+// hawkey
+#include "dnf-advisory.h"
+#include "dnf-advisorypkg.h"
+#include "dnf-advisoryref.h"
+#include "hy-goal.h"
+#include "hy-package.h"
+#include "hy-query.h"
+#include "hy-subject.h"
+#include "hy-types.h"
+#include "hy-util.h"
+#include "dnf-version.h"
+#include "libdnf/sack/query.hpp"
+
+// pyhawkey
+#include "advisory-py.hpp"
+#include "advisorypkg-py.hpp"
+#include "advisoryref-py.hpp"
+#include "exception-py.hpp"
+#include "goal-py.hpp"
+#include "nevra-py.hpp"
+#include "nsvcap-py.hpp"
+#include "package-py.hpp"
+#include "packagedelta-py.hpp"
+#include "query-py.hpp"
+#include "reldep-py.hpp"
+#include "repo-py.hpp"
+#include "sack-py.hpp"
+#include "selector-py.hpp"
+#include "subject-py.hpp"
+
+#include "pycomp.hpp"
+
+static PyObject *
+detect_arch(PyObject *unused, PyObject *args) try
+{
+ char *arch;
+
+ if (ret2e(hy_detect_arch(&arch), "Failed detecting architecture."))
+ return NULL;
+ PyObject * pyArch = PyString_FromString(arch);
+ g_free(arch);
+ return pyArch;
+} CATCH_TO_PYTHON
+
+static PyObject *
+chksum_name(PyObject *unused, PyObject *args) try
+{
+ int i;
+ const char *name;
+
+ if (!PyArg_ParseTuple(args, "i", &i))
+ return NULL;
+ name = hy_chksum_name(i);
+ if (name == NULL) {
+ PyErr_Format(PyExc_ValueError, "unrecognized chksum type: %d", i);
+ return NULL;
+ }
+
+ return PyString_FromString(name);
+} CATCH_TO_PYTHON
+
+static PyObject *
+chksum_type(PyObject *unused, PyObject *str_o) try
+{
+ PycompString str(str_o);
+ if (!str.getCString())
+ return NULL;
+
+ int type = hy_chksum_type(str.getCString());
+ if (type == 0) {
+ PyErr_Format(PyExc_ValueError, "unrecognized chksum type: %s", str.getCString());
+ return NULL;
+ }
+ return PyLong_FromLong(type);
+} CATCH_TO_PYTHON
+
+static PyObject *
+split_nevra(PyObject *unused, PyObject *nevra_o) try
+{
+ PycompString nevra(nevra_o);
+ if (!nevra.getCString())
+ return NULL;
+
+ int epoch;
+ char *name, *version, *release, *arch;
+ int split_nevra_ret = hy_split_nevra(nevra.getCString(), &name, &epoch, &version, &release, &arch);
+
+ if (ret2e(split_nevra_ret, "Failed parsing NEVRA."))
+ return NULL;
+
+ PyObject *ret = Py_BuildValue("slsss", name, epoch, version, release, arch);
+ return ret;
+} CATCH_TO_PYTHON
+
+static struct PyMethodDef hawkey_methods[] = {
+ {"chksum_name", (PyCFunction)chksum_name,
+ METH_VARARGS, NULL},
+ {"chksum_type", (PyCFunction)chksum_type,
+ METH_O, NULL},
+ {"detect_arch", (PyCFunction)detect_arch,
+ METH_NOARGS, NULL},
+ {"split_nevra", (PyCFunction)split_nevra,
+ METH_O, NULL},
+ {NULL} /* sentinel */
+};
+
+PYCOMP_MOD_INIT(_hawkey)
+{
+ PyObject *m;
+ PYCOMP_MOD_DEF(m, "_hawkey", hawkey_methods)
+
+ if (!m)
+ return PYCOMP_MOD_ERROR_VAL;
+ /* exceptions */
+ if (!init_exceptions())
+ return PYCOMP_MOD_ERROR_VAL;
+ PyModule_AddObject(m, "Exception", HyExc_Exception);
+ PyModule_AddObject(m, "ValueException", HyExc_Value);
+ PyModule_AddObject(m, "QueryException", HyExc_Query);
+ PyModule_AddObject(m, "ArchException", HyExc_Arch);
+ PyModule_AddObject(m, "RuntimeException", HyExc_Runtime);
+ PyModule_AddObject(m, "ValidationException", HyExc_Validation);
+
+ /* _hawkey.Sack */
+ if (PyType_Ready(&sack_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&sack_Type);
+ PyModule_AddObject(m, "Sack", (PyObject *)&sack_Type);
+ /* _hawkey.Advisory */
+ if (PyType_Ready(&advisory_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&advisory_Type);
+ PyModule_AddObject(m, "Advisory", (PyObject *)&advisory_Type);
+ /* _hawkey.AdvisoryPkg */
+ if (PyType_Ready(&advisorypkg_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&advisorypkg_Type);
+ PyModule_AddObject(m, "AdvisoryPkg", (PyObject *)&advisorypkg_Type);
+ /* _hawkey.AdvisoryRef */
+ if (PyType_Ready(&advisoryref_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&advisoryref_Type);
+ PyModule_AddObject(m, "AdvisoryRef", (PyObject *)&advisoryref_Type);
+ /* _hawkey.Goal */
+ if (PyType_Ready(&goal_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&goal_Type);
+ PyModule_AddObject(m, "Goal", (PyObject *)&goal_Type);
+ /* _hawkey.Package */
+ if (PyType_Ready(&package_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&package_Type);
+ PyModule_AddObject(m, "Package", (PyObject *)&package_Type);
+ /* _hawkey.PackageDelta */
+ if (PyType_Ready(&packageDelta_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&packageDelta_Type);
+ PyModule_AddObject(m, "PackageDelta", (PyObject *)&packageDelta_Type);
+ /* _hawkey.Query */
+ if (PyType_Ready(&query_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&query_Type);
+ PyModule_AddObject(m, "Query", (PyObject *)&query_Type);
+ /* _hawkey.Reldep */
+ if (PyType_Ready(&reldep_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&reldep_Type);
+ PyModule_AddObject(m, "Reldep", (PyObject *)&reldep_Type);
+ /* _hawkey.Selector */
+ if (PyType_Ready(&selector_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&selector_Type);
+ PyModule_AddObject(m, "Selector", (PyObject *)&selector_Type);
+ /* _hawkey.Repo */
+ if (PyType_Ready(&repo_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&repo_Type);
+ PyModule_AddObject(m, "Repo", (PyObject *)&repo_Type);
+ /* _hawkey.NEVRA */
+ if (PyType_Ready(&nevra_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&nevra_Type);
+ PyModule_AddObject(m, "NEVRA", (PyObject *)&nevra_Type);
+ /* _hawkey.NSVCAP */
+ if (PyType_Ready(&nsvcap_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&nsvcap_Type);
+ PyModule_AddObject(m, "NSVCAP", (PyObject *)&nsvcap_Type);
+ /* _hawkey.Subject */
+ if (PyType_Ready(&subject_Type) < 0)
+ return PYCOMP_MOD_ERROR_VAL;
+ Py_INCREF(&subject_Type);
+ PyModule_AddObject(m, "Subject", (PyObject *)&subject_Type);
+
+ PyModule_AddIntConstant(m, "FORM_NEVRA", HY_FORM_NEVRA);
+ PyModule_AddIntConstant(m, "FORM_NEVR", HY_FORM_NEVR);
+ PyModule_AddIntConstant(m, "FORM_NEV", HY_FORM_NEV);
+ PyModule_AddIntConstant(m, "FORM_NA", HY_FORM_NA);
+ PyModule_AddIntConstant(m, "FORM_NAME", HY_FORM_NAME);
+
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVCAP", HY_MODULE_FORM_NSVCAP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVCA", HY_MODULE_FORM_NSVCA);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVAP", HY_MODULE_FORM_NSVAP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVA", HY_MODULE_FORM_NSVA);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSAP", HY_MODULE_FORM_NSAP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSA", HY_MODULE_FORM_NSA);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVCP", HY_MODULE_FORM_NSVCP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVP", HY_MODULE_FORM_NSVP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSVC", HY_MODULE_FORM_NSVC);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSV", HY_MODULE_FORM_NSV);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NSP", HY_MODULE_FORM_NSP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NS", HY_MODULE_FORM_NS);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NAP", HY_MODULE_FORM_NAP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NA", HY_MODULE_FORM_NA);
+ PyModule_AddIntConstant(m, "MODULE_FORM_NP", HY_MODULE_FORM_NP);
+ PyModule_AddIntConstant(m, "MODULE_FORM_N", HY_MODULE_FORM_N);
+
+ PyModule_AddIntConstant(m, "VERSION_MAJOR", LIBDNF_MAJOR_VERSION);
+ PyModule_AddIntConstant(m, "VERSION_MINOR", LIBDNF_MINOR_VERSION);
+ PyModule_AddIntConstant(m, "VERSION_PATCH", LIBDNF_MICRO_VERSION);
+
+ PyModule_AddStringConstant(m, "SYSTEM_REPO_NAME", HY_SYSTEM_REPO_NAME);
+ PyModule_AddStringConstant(m, "CMDLINE_REPO_NAME", HY_CMDLINE_REPO_NAME);
+ PyModule_AddStringConstant(m, "MODULE_FAIL_SAFE_REPO_NAME", LIBDNF_MODULE_FAIL_SAFE_REPO_NAME);
+
+ PyModule_AddIntConstant(m, "PKG", HY_PKG);
+ PyModule_AddIntConstant(m, "PKG_ADVISORY", HY_PKG_ADVISORY);
+ PyModule_AddIntConstant(m, "PKG_ADVISORY_BUG", HY_PKG_ADVISORY_BUG);
+ PyModule_AddIntConstant(m, "PKG_ADVISORY_CVE", HY_PKG_ADVISORY_CVE);
+ PyModule_AddIntConstant(m, "PKG_ADVISORY_SEVERITY", HY_PKG_ADVISORY_SEVERITY);
+ PyModule_AddIntConstant(m, "PKG_ADVISORY_TYPE", HY_PKG_ADVISORY_TYPE);
+ PyModule_AddIntConstant(m, "PKG_ARCH", HY_PKG_ARCH);
+ PyModule_AddIntConstant(m, "PKG_CONFLICTS", HY_PKG_CONFLICTS);
+ PyModule_AddIntConstant(m, "PKG_DESCRIPTION", HY_PKG_DESCRIPTION);
+ PyModule_AddIntConstant(m, "PKG_DOWNGRADABLE", HY_PKG_DOWNGRADABLE);
+ PyModule_AddIntConstant(m, "PKG_DOWNGRADES", HY_PKG_DOWNGRADES);
+ PyModule_AddIntConstant(m, "PKG_EMPTY", HY_PKG_EMPTY);
+ PyModule_AddIntConstant(m, "PKG_ENHANCES", HY_PKG_ENHANCES);
+ PyModule_AddIntConstant(m, "PKG_EPOCH", HY_PKG_EPOCH);
+ PyModule_AddIntConstant(m, "PKG_EVR", HY_PKG_EVR);
+ PyModule_AddIntConstant(m, "PKG_FILE", HY_PKG_FILE);
+ PyModule_AddIntConstant(m, "PKG_LATEST_PER_ARCH_BY_PRIORITY",
+ HY_PKG_LATEST_PER_ARCH_BY_PRIORITY);
+ PyModule_AddIntConstant(m, "PKG_LATEST_PER_ARCH", HY_PKG_LATEST_PER_ARCH);
+ PyModule_AddIntConstant(m, "PKG_LATEST", HY_PKG_LATEST);
+ PyModule_AddIntConstant(m, "PKG_LOCATION", HY_PKG_LOCATION);
+ PyModule_AddIntConstant(m, "PKG_NAME", HY_PKG_NAME);
+ PyModule_AddIntConstant(m, "PKG_NEVRA", HY_PKG_NEVRA);
+ PyModule_AddIntConstant(m, "PKG_NEVRA_STRICT", HY_PKG_NEVRA_STRICT);
+ PyModule_AddIntConstant(m, "PKG_OBSOLETES", HY_PKG_OBSOLETES);
+ PyModule_AddIntConstant(m, "PKG_OBSOLETES_BY_PRIORITY", HY_PKG_OBSOLETES_BY_PRIORITY);
+ PyModule_AddIntConstant(m, "PKG_PROVIDES", HY_PKG_PROVIDES);
+ PyModule_AddIntConstant(m, "PKG_RECOMMENDS", HY_PKG_RECOMMENDS);
+ PyModule_AddIntConstant(m, "PKG_RELEASE", HY_PKG_RELEASE);
+ PyModule_AddIntConstant(m, "PKG_REPONAME", HY_PKG_REPONAME);
+ PyModule_AddIntConstant(m, "PKG_REQUIRES", HY_PKG_REQUIRES);
+ PyModule_AddIntConstant(m, "PKG_SOURCERPM", HY_PKG_SOURCERPM);
+ PyModule_AddIntConstant(m, "PKG_SUGGESTS", HY_PKG_SUGGESTS);
+ PyModule_AddIntConstant(m, "PKG_SUMMARY", HY_PKG_SUMMARY);
+ PyModule_AddIntConstant(m, "PKG_SUPPLEMENTS", HY_PKG_SUPPLEMENTS);
+ PyModule_AddIntConstant(m, "PKG_UPGRADABLE", HY_PKG_UPGRADABLE);
+ PyModule_AddIntConstant(m, "PKG_UPGRADES", HY_PKG_UPGRADES);
+ PyModule_AddIntConstant(m, "PKG_UPGRADES_BY_PRIORITY", HY_PKG_UPGRADES_BY_PRIORITY);
+ PyModule_AddIntConstant(m, "PKG_URL", HY_PKG_URL);
+ PyModule_AddIntConstant(m, "PKG_VERSION", HY_PKG_VERSION);
+
+ PyModule_AddIntConstant(m, "APPLY_EXCLUDES", static_cast<int>(
+ libdnf::Query::ExcludeFlags::APPLY_EXCLUDES));
+ PyModule_AddIntConstant(m, "IGNORE_MODULAR_EXCLUDES", static_cast<int>(
+ libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES));
+ PyModule_AddIntConstant(m, "IGNORE_REGULAR_EXCLUDES", static_cast<int>(
+ libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES));
+ PyModule_AddIntConstant(m, "IGNORE_EXCLUDES", static_cast<int>(
+ libdnf::Query::ExcludeFlags::IGNORE_EXCLUDES));
+
+ PyModule_AddIntConstant(m, "ERASE", DNF_ERASE);
+ PyModule_AddIntConstant(m, "DISTUPGRADE", DNF_DISTUPGRADE);
+ PyModule_AddIntConstant(m, "DISTUPGRADE_ALL", DNF_DISTUPGRADE_ALL);
+ PyModule_AddIntConstant(m, "DOWNGRADE", DNF_DOWNGRADE);
+ PyModule_AddIntConstant(m, "INSTALL", DNF_INSTALL);
+ PyModule_AddIntConstant(m, "UPGRADE", DNF_UPGRADE);
+ PyModule_AddIntConstant(m, "UPGRADE_ALL", DNF_UPGRADE_ALL);
+
+ PyModule_AddIntConstant(m, "ALLOW_UNINSTALL", DNF_ALLOW_UNINSTALL);
+ PyModule_AddIntConstant(m, "FORCE_BEST", DNF_FORCE_BEST);
+ PyModule_AddIntConstant(m, "VERIFY", DNF_VERIFY);
+ PyModule_AddIntConstant(m, "IGNORE_WEAK_DEPS", DNF_IGNORE_WEAK_DEPS);
+
+ PyModule_AddIntConstant(m, "CHKSUM_MD5", G_CHECKSUM_MD5);
+ PyModule_AddIntConstant(m, "CHKSUM_SHA1", G_CHECKSUM_SHA1);
+ PyModule_AddIntConstant(m, "CHKSUM_SHA256", G_CHECKSUM_SHA256);
+ PyModule_AddIntConstant(m, "CHKSUM_SHA384", G_CHECKSUM_SHA384);
+ PyModule_AddIntConstant(m, "CHKSUM_SHA512", G_CHECKSUM_SHA512);
+
+ PyModule_AddIntConstant(m, "ICASE", HY_ICASE);
+ PyModule_AddIntConstant(m, "EQ", HY_EQ);
+ PyModule_AddIntConstant(m, "LT", HY_LT);
+ PyModule_AddIntConstant(m, "GT", HY_GT);
+ PyModule_AddIntConstant(m, "NEQ", HY_NEQ);
+ PyModule_AddIntConstant(m, "NOT", HY_NOT);
+ PyModule_AddIntConstant(m, "SUBSTR", HY_SUBSTR);
+ PyModule_AddIntConstant(m, "GLOB", HY_GLOB);
+
+ PyModule_AddIntConstant(m, "REASON_DEP", HY_REASON_DEP);
+ PyModule_AddIntConstant(m, "REASON_USER", HY_REASON_USER);
+ PyModule_AddIntConstant(m, "REASON_CLEAN", HY_REASON_CLEAN);
+ PyModule_AddIntConstant(m, "REASON_WEAKDEP", HY_REASON_WEAKDEP);
+
+ PyModule_AddIntConstant(m, "ADVISORY_UNKNOWN", DNF_ADVISORY_KIND_UNKNOWN);
+ PyModule_AddIntConstant(m, "ADVISORY_SECURITY", DNF_ADVISORY_KIND_SECURITY);
+ PyModule_AddIntConstant(m, "ADVISORY_BUGFIX", DNF_ADVISORY_KIND_BUGFIX);
+ PyModule_AddIntConstant(m, "ADVISORY_ENHANCEMENT", DNF_ADVISORY_KIND_ENHANCEMENT);
+ PyModule_AddIntConstant(m, "ADVISORY_NEWPACKAGE", DNF_ADVISORY_KIND_NEWPACKAGE);
+
+ PyModule_AddIntConstant(m, "REFERENCE_UNKNOWN", DNF_REFERENCE_KIND_UNKNOWN);
+ PyModule_AddIntConstant(m, "REFERENCE_BUGZILLA", DNF_REFERENCE_KIND_BUGZILLA);
+ PyModule_AddIntConstant(m, "REFERENCE_CVE", DNF_REFERENCE_KIND_CVE);
+ PyModule_AddIntConstant(m, "REFERENCE_VENDOR", DNF_REFERENCE_KIND_VENDOR);
+
+ bind_textdomain_codeset(GETTEXT_DOMAIN, "UTF-8");
+
+ return PYCOMP_MOD_SUCCESS_VAL(m);
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Python.h"
+#include <vector>
+#include <string>
+#include <ctime>
+#include <datetime.h>
+
+#include "dnf-advisory.h"
+#include "dnf-advisorypkg.h"
+#include "dnf-advisoryref.h"
+#include "hy-packageset.h"
+#include "dnf-reldep.h"
+#include "dnf-reldep-list.h"
+#include "hy-iutil.h"
+#include "hy-util-private.hpp"
+#include "advisory-py.hpp"
+#include "advisorypkg-py.hpp"
+#include "advisoryref-py.hpp"
+#include "iutil-py.hpp"
+#include "package-py.hpp"
+#include "query-py.hpp"
+#include "reldep-py.hpp"
+#include "sack-py.hpp"
+#include "pycomp.hpp"
+#include "sack/advisorypkg.hpp"
+#include "sack/changelog.hpp"
+#include "sack/packageset.hpp"
+#include "sack/query.hpp"
+
+#include "../../libdnf/repo/solvable/Dependency.hpp"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+
+UniquePtrPyObject & UniquePtrPyObject::operator =(UniquePtrPyObject && src) noexcept
+{
+ if (this == &src)
+ return *this;
+ Py_XDECREF(pyObj);
+ pyObj = src.pyObj;
+ src.pyObj = NULL;
+ return *this;
+}
+
+void UniquePtrPyObject::reset(PyObject * pyObj) noexcept
+{
+ Py_XDECREF(this->pyObj);
+ this->pyObj = pyObj;
+}
+
+UniquePtrPyObject::~UniquePtrPyObject()
+{
+ Py_XDECREF(pyObj);
+}
+
+PyObject *
+advisorylist_to_pylist(const GPtrArray *advisorylist, PyObject *sack)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ for (unsigned int i = 0; i < advisorylist->len; ++i) {
+ auto cadvisory =
+ static_cast<DnfAdvisory *>(g_steal_pointer(&g_ptr_array_index(advisorylist, i)));
+ UniquePtrPyObject advisory(advisoryToPyObject(cadvisory, sack));
+
+ if (!advisory)
+ return NULL;
+
+ int rc = PyList_Append(list.get(), advisory.get());
+ if (rc == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+PyObject *
+advisoryPkgVectorToPylist(const std::vector<libdnf::AdvisoryPkg> & advisorypkgs)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ for (auto& advisorypkg : advisorypkgs) {
+ UniquePtrPyObject pyAdvisoryPkg(advisorypkgToPyObject(new libdnf::AdvisoryPkg(advisorypkg)));
+ if (!pyAdvisoryPkg)
+ return NULL;
+ int rc = PyList_Append(list.get(), pyAdvisoryPkg.get());
+ if (rc == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+PyObject *
+advisoryRefVectorToPylist(const std::vector<libdnf::AdvisoryRef> & advisoryRefs, PyObject *sack)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ for (auto& advisoryRef : advisoryRefs) {
+ UniquePtrPyObject pyAdvisoryRef(advisoryrefToPyObject(new libdnf::AdvisoryRef(advisoryRef), sack));
+ if (!pyAdvisoryRef)
+ return NULL;
+ int rc = PyList_Append(list.get(), pyAdvisoryRef.get());
+ if (rc == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+PyObject *
+changelogslist_to_pylist(const std::vector<libdnf::Changelog> & changelogslist)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+ PyDateTime_IMPORT;
+
+ for (auto & citem: changelogslist) {
+ UniquePtrPyObject d(PyDict_New());
+ if (!d)
+ return NULL;
+ UniquePtrPyObject author(PyUnicode_FromString(citem.getAuthor().c_str()));
+ if (PyDict_SetItemString(d.get(), "author", author.get()) == -1)
+ return NULL;
+ UniquePtrPyObject description(PyUnicode_FromString(citem.getText().c_str()));
+ if (PyDict_SetItemString(d.get(), "text", description.get()) == -1)
+ return NULL;
+ time_t itemts=citem.getTimestamp();
+ struct tm ts;
+ ts = *localtime(&itemts);
+ UniquePtrPyObject timestamp(PyDate_FromDate(ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday));
+ if (PyDict_SetItemString(d.get(), "timestamp", timestamp.get()) == -1)
+ return NULL;
+ if (PyList_Append(list.get(), d.get()) == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+PyObject *
+packagelist_to_pylist(GPtrArray *plist, PyObject *sack)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ for (unsigned int i = 0; i < plist->len; i++) {
+ auto cpkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, i));
+ UniquePtrPyObject package(new_package(sack, dnf_package_get_id(cpkg)));
+ if (!package)
+ return NULL;
+
+ int rc = PyList_Append(list.get(), package.get());
+ if (rc == -1)
+ return NULL;
+ }
+ return list.release();
+}
+
+PyObject *
+packageset_to_pylist(const DnfPackageSet *pset, PyObject *sack)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ Id id = -1;
+ while(true) {
+ id = pset->next(id);
+ if (id == -1)
+ break;
+ UniquePtrPyObject package(new_package(sack, id));
+ if (!package)
+ return NULL;
+
+ int rc = PyList_Append(list.get(), package.get());
+ if (rc == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+std::unique_ptr<DnfPackageSet>
+pyseq_to_packageset(PyObject *obj, DnfSack *sack)
+{
+ if (queryObject_Check(obj)) {
+ HyQuery target = queryFromPyObject(obj);
+ return std::unique_ptr<DnfPackageSet>(new libdnf::PackageSet(*target->runSet()));
+ }
+
+ UniquePtrPyObject sequence(PySequence_Fast(obj, "Expected a sequence."));
+ if (!sequence)
+ return NULL;
+ std::unique_ptr<DnfPackageSet> pset(new libdnf::PackageSet(sack));
+
+ const unsigned count = PySequence_Size(sequence.get());
+ for (unsigned int i = 0; i < count; ++i) {
+ PyObject *item = PySequence_Fast_GET_ITEM(sequence.get(), i);
+ if (item == NULL)
+ return NULL;
+ DnfPackage *pkg = packageFromPyObject(item);
+ if (pkg == NULL)
+ return NULL;
+ pset->set(pkg);
+ }
+
+ return pset;
+}
+
+std::unique_ptr<libdnf::DependencyContainer>
+pyseq_to_reldeplist(PyObject *obj, DnfSack *sack, int cmp_type)
+{
+ UniquePtrPyObject sequence(PySequence_Fast(obj, "Expected a sequence."));
+ if (!sequence)
+ return NULL;
+ std::unique_ptr<libdnf::DependencyContainer> reldeplist(new libdnf::DependencyContainer(sack));
+
+ const unsigned count = PySequence_Size(sequence.get());
+ for (unsigned int i = 0; i < count; ++i) {
+ PyObject *item = PySequence_Fast_GET_ITEM(sequence.get(), i);
+ if (item == NULL)
+ return NULL;
+ if (reldepObject_Check(item)) {
+ DnfReldep * reldep = reldepFromPyObject(item);
+ if (reldep == NULL)
+ return NULL;
+ reldeplist->add(reldep);
+ } else if (cmp_type == HY_GLOB) {
+
+ PycompString reldep_str(item);
+ if (!reldep_str.getCString())
+ return NULL;
+
+ if (!hy_is_glob_pattern(reldep_str.getCString())) {
+ if (!reldeplist->addReldep(reldep_str.getCString()))
+ continue;
+ } else {
+ if (!reldeplist->addReldepWithGlob(reldep_str.getCString()))
+ continue;
+ }
+
+ } else {
+ PycompString reldepStr(item);
+ if (!reldepStr.getCString())
+ return NULL;
+ if (!reldeplist->addReldep(reldepStr.getCString()))
+ continue;
+ }
+ }
+
+ return reldeplist;
+}
+
+PyObject *
+strlist_to_pylist(const char **slist)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ for (const char **iter = slist; *iter; ++iter) {
+ UniquePtrPyObject str(PyUnicode_DecodeUTF8(*iter, strlen(*iter), "surrogateescape"));
+ if (!str)
+ return NULL;
+ int rc = PyList_Append(list.get(), str.get());
+ if (rc == -1)
+ return NULL;
+ }
+ return list.release();
+}
+
+PyObject *
+strCpplist_to_pylist(const std::vector<std::string> & cppList)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+ for (auto & cStr:cppList) {
+ UniquePtrPyObject str(PyUnicode_FromString(cStr.c_str()));
+ if (!str)
+ return NULL;
+ int rc = PyList_Append(list.get(), str.get());
+ if (rc == -1)
+ return NULL;
+ }
+ return list.release();
+}
+
+PyObject *
+reldeplist_to_pylist(DnfReldepList *reldeplist, PyObject *sack)
+{
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+
+ const int count = reldeplist->count();
+ for (int i = 0; i < count; ++i) {
+ UniquePtrPyObject reldep(new_reldep(sack, reldeplist->getId(i)));
+
+ if (!reldep)
+ return NULL;
+
+ int rc = PyList_Append(list.get(), reldep.get());
+ if (rc == -1)
+ return NULL;
+ }
+
+ return list.release();
+}
+
+std::vector<std::string>
+pySequenceConverter(PyObject * pySequence)
+{
+ UniquePtrPyObject seq(PySequence_Fast(pySequence, "Expected a sequence."));
+ if (!seq)
+ throw std::runtime_error("Expected a sequence.");
+ const unsigned count = PySequence_Size(seq.get());
+ std::vector<std::string> output;
+ output.reserve(count);
+ for (unsigned int i = 0; i < count; ++i) {
+ PyObject *item = PySequence_Fast_GET_ITEM(seq.get(), i);
+ if (PyUnicode_Check(item) || PyString_Check(item)) {
+ PycompString pycomStr(item);
+ if (!pycomStr.getCString())
+ throw std::runtime_error("Invalid value.");
+ output.push_back(pycomStr.getCString());
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Invalid value.");
+ throw std::runtime_error("Invalid value.");
+ }
+ }
+ return output;
+}
+
+PyObject *
+problemRulesPyConverter(std::vector<std::vector<std::string>> & allProblems)
+{
+ UniquePtrPyObject list_output(PyList_New(0));
+ if (!list_output)
+ return NULL;
+ for (auto & problemList: allProblems) {
+ if (problemList.empty()) {
+ PyErr_SetString(PyExc_ValueError, "Index out of range.");
+ continue;
+ }
+ UniquePtrPyObject list(strCpplist_to_pylist(problemList));
+ int rc = PyList_Append(list_output.get(), list.get());
+ if (rc == -1)
+ return NULL;
+ }
+ return list_output.release();
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IUTIL_PY_H
+#define IUTIL_PY_H
+
+#include <vector>
+
+#include "hy-types.h"
+#include "dnf-sack.h"
+#include "sack/advisorypkg.hpp"
+#include "sack/changelog.hpp"
+
+#define TEST_COND(cond) \
+ ((cond) ? Py_True : Py_False)
+
+/**
+* @brief Smart pointer to PyObject
+*
+* Owns and manages PyObject. Decrements the reference count for the PyObject
+* (calls Py_XDECREF on it) when UniquePtrPyObject goes out of scope.
+*
+* Implements subset of standard std::unique_ptr methods.
+*/
+class UniquePtrPyObject {
+public:
+ constexpr UniquePtrPyObject() noexcept : pyObj(NULL) {}
+ explicit UniquePtrPyObject(PyObject * pyObj) noexcept : pyObj(pyObj) {}
+ UniquePtrPyObject(UniquePtrPyObject && src) noexcept : pyObj(src.pyObj) { src.pyObj = NULL; }
+ UniquePtrPyObject & operator =(UniquePtrPyObject && src) noexcept;
+ explicit operator bool() const noexcept { return pyObj != NULL; }
+ PyObject * get() const noexcept { return pyObj; }
+ PyObject * release() noexcept;
+ void reset(PyObject * pyObj = NULL) noexcept;
+ ~UniquePtrPyObject();
+private:
+ PyObject * pyObj;
+};
+
+inline PyObject * UniquePtrPyObject::release() noexcept
+{
+ auto tmpObj = pyObj;
+ pyObj = NULL;
+ return tmpObj;
+}
+
+std::vector<std::string> pySequenceConverter(PyObject * pySequence);
+PyObject *advisorylist_to_pylist(const GPtrArray *advisorylist, PyObject *sack);
+PyObject *advisoryPkgVectorToPylist(const std::vector<libdnf::AdvisoryPkg> & advisorypkgs);
+PyObject *advisoryRefVectorToPylist(const std::vector<libdnf::AdvisoryRef> & advisoryRefs,
+ PyObject *sack);
+PyObject *changelogslist_to_pylist(const std::vector<libdnf::Changelog> & changelogslist);
+PyObject *packagelist_to_pylist(GPtrArray *plist, PyObject *sack);
+PyObject * packageset_to_pylist(const DnfPackageSet * pset, PyObject * sack);
+std::unique_ptr<DnfPackageSet> pyseq_to_packageset(PyObject * sequence, DnfSack * sack);
+std::unique_ptr<DnfReldepList> pyseq_to_reldeplist(PyObject *sequence, DnfSack *sack, int cmp_type);
+PyObject *strlist_to_pylist(const char **slist);
+PyObject * strCpplist_to_pylist(const std::vector<std::string> & cppList);
+PyObject *reldeplist_to_pylist(DnfReldepList *reldeplist, PyObject *sack);
+PyObject * problemRulesPyConverter(std::vector<std::vector<std::string>> & allProblems);
+
+#endif // IUTIL_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// libsolv
+#include <solv/util.h>
+
+// hawkey
+#include "hy-query.h"
+#include "dnf-sack.h"
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+#include "nevra-py.hpp"
+#include "pycomp.hpp"
+#include "query-py.hpp"
+#include "sack-py.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ libdnf::Nevra *nevra;
+} _NevraObject;
+
+libdnf::Nevra *
+nevraFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &nevra_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a _hawkey.NEVRA object.");
+ return NULL;
+ }
+ return ((_NevraObject *)o)->nevra;
+}
+
+PyObject *
+nevraToPyObject(libdnf::Nevra *nevra)
+{
+ _NevraObject *self = (_NevraObject *)nevra_Type.tp_alloc(&nevra_Type, 0);
+ if (self)
+ self->nevra = nevra;
+ return (PyObject *)self;
+}
+
+// getsetters
+static int
+set_epoch(_NevraObject *self, PyObject *value, void *closure) try
+{
+ if (value == NULL)
+ self->nevra->setEpoch(libdnf::Nevra::EPOCH_NOT_SET);
+ else if (PyInt_Check(value))
+ self->nevra->setEpoch(PyLong_AsLong(value));
+ else if (value == Py_None)
+ self->nevra->setEpoch(libdnf::Nevra::EPOCH_NOT_SET);
+ else
+ return -1;
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+get_epoch(_NevraObject *self, void *closure) try
+{
+ if (self->nevra->getEpoch() == libdnf::Nevra::EPOCH_NOT_SET)
+ Py_RETURN_NONE;
+#if PY_MAJOR_VERSION >= 3
+ return PyLong_FromLong(self->nevra->getEpoch());
+#else
+ return PyInt_FromLong(self->nevra->getEpoch());
+#endif
+} CATCH_TO_PYTHON
+
+template<const std::string & (libdnf::Nevra::*getMethod)() const>
+static PyObject *
+get_attr(_NevraObject *self, void *closure) try
+{
+ auto str = (self->nevra->*getMethod)();
+ if (str.empty())
+ Py_RETURN_NONE;
+ else
+ return PyString_FromString(str.c_str());
+} CATCH_TO_PYTHON
+
+template<void (libdnf::Nevra::*setMethod)(std::string &&)>
+static int
+set_attr(_NevraObject *self, PyObject *value, void *closure) try
+{
+ PycompString str_value(value);
+ if (!str_value.getCString())
+ return -1;
+ (self->nevra->*setMethod)(str_value.getCString());
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyGetSetDef nevra_getsetters[] = {
+ {(char*)"name", (getter)get_attr<&libdnf::Nevra::getName>,
+ (setter)set_attr<&libdnf::Nevra::setName>, NULL, NULL},
+ {(char*)"epoch", (getter)get_epoch, (setter)set_epoch,
+ NULL, NULL},
+ {(char*)"version", (getter)get_attr<&libdnf::Nevra::getVersion>,
+ (setter)set_attr<&libdnf::Nevra::setVersion>, NULL, NULL},
+ {(char*)"release", (getter)get_attr<&libdnf::Nevra::getRelease>,
+ (setter)set_attr<&libdnf::Nevra::setRelease>, NULL, NULL},
+ {(char*)"arch", (getter)get_attr<&libdnf::Nevra::getArch>,
+ (setter)set_attr<&libdnf::Nevra::setArch>, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+nevra_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _NevraObject *self = (_NevraObject*)type->tp_alloc(type, 0);
+ if (self)
+ self->nevra = new libdnf::Nevra;
+ return (PyObject*)self;
+} CATCH_TO_PYTHON
+
+static void
+nevra_dealloc(_NevraObject *self)
+{
+ delete self->nevra;
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+nevra_init(_NevraObject *self, PyObject *args, PyObject *kwds) try
+{
+ char *name = NULL, *version = NULL, *release = NULL, *arch = NULL;
+ PyObject *epoch_o = NULL;
+ libdnf::Nevra * cnevra = NULL;
+
+ const char *kwlist[] = {"name", "epoch", "version", "release", "arch",
+ "nevra", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zOzzzO&", (char**) kwlist,
+ &name, &epoch_o, &version, &release, &arch, nevra_converter, &cnevra))
+ return -1;
+ if (!name && !cnevra) {
+ PyErr_SetString(PyExc_ValueError,
+ "Name is required parameter.");
+ return -1;
+ }
+ if (cnevra) {
+ *self->nevra = *cnevra;
+ return 0;
+ }
+ if (set_epoch(self, epoch_o, NULL) == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "An integer value or None expected for epoch.");
+ return -1;
+ }
+ if (name)
+ self->nevra->setName(name);
+ if (version)
+ self->nevra->setVersion(version);
+ if (release)
+ self->nevra->setRelease(release);
+ if (arch)
+ self->nevra->setArch(arch);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+/* object methods */
+
+static PyObject *
+evr(_NevraObject *self, PyObject *unused) try
+{
+ return PyString_FromString(self->nevra->getEvr().c_str());
+} CATCH_TO_PYTHON
+
+int
+nevra_converter(PyObject *o, libdnf::Nevra **nevra_ptr)
+{
+ auto nevra = nevraFromPyObject(o);
+ if (nevra == NULL)
+ return 0;
+ *nevra_ptr = nevra;
+ return 1;
+}
+
+static PyObject *
+evr_cmp(_NevraObject *self, PyObject *args) try
+{
+ DnfSack *sack;
+ libdnf::Nevra *nevra;
+ if (!PyArg_ParseTuple(args, "O&O&", nevra_converter, &nevra, sack_converter, &sack)) {
+ return NULL;
+ }
+ if (sack == NULL || nevra == NULL)
+ return NULL;
+ int cmp = self->nevra->compareEvr(*nevra, sack);
+ return PyLong_FromLong(cmp);
+} CATCH_TO_PYTHON
+
+static PyObject *
+has_just_name(_NevraObject *self, PyObject *unused) try
+{
+ return PyBool_FromLong(self->nevra->hasJustName());
+} CATCH_TO_PYTHON
+
+static PyObject *
+to_query(_NevraObject *self, PyObject *args, PyObject *kwds) try
+{
+ PyObject *sack;
+ DnfSack *csack;
+ const char *kwlist[] = {"sack", "icase", NULL};
+ PyObject *icase = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!", (char**) kwlist, &sack_Type, &sack,
+ &PyBool_Type, &icase)) {
+ return NULL;
+ }
+ gboolean c_icase = icase!=NULL && PyObject_IsTrue(icase);
+ csack = sackFromPyObject(sack);
+ HyQuery query = hy_query_from_nevra(self->nevra, csack, c_icase);
+ PyObject *q = queryToPyObject(query, sack, &query_Type);
+ return q;
+} CATCH_TO_PYTHON
+
+static struct PyMethodDef nevra_methods[] = {
+ {"evr_cmp", (PyCFunction) evr_cmp, METH_VARARGS, NULL},
+ {"evr", (PyCFunction) evr, METH_NOARGS, NULL},
+ {"has_just_name", (PyCFunction) has_just_name, METH_NOARGS, NULL},
+ {"to_query", (PyCFunction) to_query, METH_VARARGS | METH_KEYWORDS, NULL},
+
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+nevra_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *v;
+ libdnf::Nevra *other_nevra, *self_nevra;
+ other_nevra = nevraFromPyObject(other);
+ self_nevra = nevraFromPyObject(self);
+
+ if (!other_nevra) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ long result = self_nevra->compare(*other_nevra);
+
+ switch (op) {
+ case Py_EQ:
+ v = TEST_COND(result == 0);
+ break;
+ case Py_NE:
+ v = TEST_COND(result != 0);
+ break;
+ case Py_LE:
+ v = TEST_COND(result <= 0);
+ break;
+ case Py_GE:
+ v = TEST_COND(result >= 0);
+ break;
+ case Py_LT:
+ v = TEST_COND(result < 0);
+ break;
+ case Py_GT:
+ v = TEST_COND(result > 0);
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+ Py_INCREF(v);
+ return v;
+} CATCH_TO_PYTHON
+
+PyTypeObject nevra_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.NEVRA", /*tp_name*/
+ sizeof(_NevraObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) nevra_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "NEVRA object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ nevra_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ nevra_methods, /* tp_methods */
+ 0, /* tp_members */
+ nevra_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)nevra_init, /* tp_init */
+ 0, /* tp_alloc */
+ nevra_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef NEVRA_PY_H
+#define NEVRA_PY_H
+
+#include "nevra.hpp"
+
+extern PyTypeObject nevra_Type;
+
+libdnf::Nevra *nevraFromPyObject(PyObject *o);
+PyObject *nevraToPyObject(libdnf::Nevra *nevra);
+int nevra_converter(PyObject *o, libdnf::Nevra **nevra_ptr);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+#include "nsvcap-py.hpp"
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ libdnf::Nsvcap * nsvcap;
+} _NsvcapObject;
+
+libdnf::Nsvcap *
+nsvcapFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &nsvcap_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a _hawkey.Nsvcap object.");
+ return NULL;
+ }
+ return ((_NsvcapObject *)o)->nsvcap;
+}
+
+PyObject *
+nsvcapToPyObject(libdnf::Nsvcap * nsvcap)
+{
+ _NsvcapObject *self = (_NsvcapObject *)nsvcap_Type.tp_alloc(&nsvcap_Type, 0);
+ if (self)
+ self->nsvcap = nsvcap;
+ return (PyObject *)self;
+}
+
+// getsetters
+template<const std::string & (libdnf::Nsvcap::*getMethod)() const>
+static PyObject *
+get_attr(_NsvcapObject *self, void *closure) try
+{
+ auto str = (self->nsvcap->*getMethod)();
+
+ if (str.empty())
+ Py_RETURN_NONE;
+ else
+ return PyString_FromString(str.c_str());
+} CATCH_TO_PYTHON
+
+template<void (libdnf::Nsvcap::*setMethod)(std::string &&)>
+static int
+set_attr(_NsvcapObject *self, PyObject *value, void *closure) try
+{
+ PycompString str_value(value);
+ if (!str_value.getCString())
+ return -1;
+ (self->nsvcap->*setMethod)(str_value.getCString());
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyGetSetDef nsvcap_getsetters[] = {
+ {(char*)"name", (getter)get_attr<&libdnf::Nsvcap::getName>,
+ (setter)set_attr<&libdnf::Nsvcap::setName>, NULL, NULL},
+ {(char*)"stream", (getter)get_attr<&libdnf::Nsvcap::getStream>,
+ (setter)set_attr<&libdnf::Nsvcap::setStream>, NULL, NULL},
+ {(char*)"version", (getter)get_attr<&libdnf::Nsvcap::getVersion>,
+ (setter)set_attr<&libdnf::Nsvcap::setVersion>, NULL, NULL},
+ {(char*)"context", (getter)get_attr<&libdnf::Nsvcap::getContext>,
+ (setter)set_attr<&libdnf::Nsvcap::setContext>, NULL, NULL},
+ {(char*)"arch", (getter)get_attr<&libdnf::Nsvcap::getArch>,
+ (setter)set_attr<&libdnf::Nsvcap::setArch>, NULL, NULL},
+ {(char*)"profile", (getter)get_attr<&libdnf::Nsvcap::getProfile>,
+ (setter)set_attr<&libdnf::Nsvcap::setProfile>, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+nsvcap_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _NsvcapObject *self = (_NsvcapObject*)type->tp_alloc(type, 0);
+ if (self)
+ self->nsvcap = new libdnf::Nsvcap;
+ return (PyObject*)self;
+} CATCH_TO_PYTHON
+
+static void
+nsvcap_dealloc(_NsvcapObject *self)
+{
+ delete self->nsvcap;
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+nsvcap_init(_NsvcapObject *self, PyObject *args, PyObject *kwds) try
+{
+ char *name = NULL, *stream = NULL, *version = NULL, *context = NULL, *arch = NULL, *profile = NULL;
+ libdnf::Nsvcap * cNsvcap = NULL;
+
+ const char *kwlist[] = {"name", "stream", "version", "context", "arch", "profile",
+ "nsvcap", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzzzzzO&", (char**) kwlist,
+ &name, &stream, &version, &context, &arch, &profile, nsvcapConverter,
+ &cNsvcap))
+ return -1;
+ if (!name && !cNsvcap) {
+ PyErr_SetString(PyExc_ValueError, "Name is required parameter.");
+ return -1;
+ }
+ if (cNsvcap) {
+ *self->nsvcap = *cNsvcap;
+ return 0;
+ }
+
+ self->nsvcap->setName(name);
+ if (stream) {
+ self->nsvcap->setStream(stream);
+ }
+ if (version) {
+ self->nsvcap->setVersion(version);
+ }
+ if (context) {
+ self->nsvcap->setContext(context);
+ }
+ if (arch) {
+ self->nsvcap->setArch(arch);
+ }
+ if (profile) {
+ self->nsvcap->setProfile(profile);
+ }
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+/* object methods */
+
+int
+nsvcapConverter(PyObject *o, libdnf::Nsvcap ** nsvcap_ptr)
+{
+ libdnf::Nsvcap * nsvcap = nsvcapFromPyObject(o);
+ if (!nsvcap)
+ return 0;
+ *nsvcap_ptr = nsvcap;
+ return 1;
+}
+
+PyTypeObject nsvcap_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.NSVCAP", /*tp_name*/
+ sizeof(_NsvcapObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) nsvcap_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "NSVCAP object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ nsvcap_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc) nsvcap_init, /* tp_init */
+ 0, /* tp_alloc */
+ nsvcap_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.`
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBDNF_NSVCAP_PY_H
+#define LIBDNF_NSVCAP_PY_H
+
+#include "nsvcap.hpp"
+
+extern PyTypeObject nsvcap_Type;
+
+libdnf::Nsvcap * nsvcapFromPyObject(PyObject *o);
+PyObject *nsvcapToPyObject(libdnf::Nsvcap * nsvcap);
+int nsvcapConverter(PyObject *o, libdnf::Nsvcap ** nsvcap_ptr);
+
+#endif //LIBDNF_NSVCAP_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <stdio.h>
+
+#include <solv/util.h>
+
+#include "dnf-advisory.h"
+#include "hy-iutil.h"
+#include "hy-package.h"
+#include "hy-package-private.hpp"
+#include "dnf-package.h"
+#include "dnf-reldep.h"
+#include "dnf-types.h"
+#include "libdnf/sack/packageset.hpp"
+
+#include "exception-py.hpp"
+#include "iutil-py.hpp"
+#include "package-py.hpp"
+#include "packagedelta-py.hpp"
+#include "sack-py.hpp"
+#include "pycomp.hpp"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfPackage *package;
+ PyObject *sack;
+} _PackageObject;
+
+long package_hash(_PackageObject *self);
+
+DnfPackage *
+packageFromPyObject(PyObject *o)
+{
+ if (!PyType_IsSubtype(o->ob_type, &package_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a Package object.");
+ return NULL;
+ }
+ return ((_PackageObject *)o)->package;
+}
+
+int
+package_converter(PyObject *o, DnfPackage **pkg_ptr)
+{
+ DnfPackage *pkg = packageFromPyObject(o);
+ if (pkg == NULL)
+ return 0;
+ *pkg_ptr = pkg;
+ return 1;
+}
+
+/* functions on the type */
+
+static PyObject *
+package_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _PackageObject *self = (_PackageObject*)type->tp_alloc(type, 0);
+ if (self) {
+ self->sack = NULL;
+ self->package = NULL;
+ }
+ return (PyObject*)self;
+} CATCH_TO_PYTHON
+
+static void
+package_dealloc(_PackageObject *self)
+{
+ if (self->package)
+ g_object_unref(self->package);
+
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+package_init(_PackageObject *self, PyObject *args, PyObject *kwds) try
+{
+ Id id;
+ PyObject *sack;
+ DnfSack *csack;
+
+ if (!PyArg_ParseTuple(args, "(O!i)", &sack_Type, &sack, &id))
+ return -1;
+ csack = sackFromPyObject(sack);
+ if (csack == NULL)
+ return -1;
+ self->sack = sack;
+ Py_INCREF(self->sack);
+ self->package = dnf_package_new(csack, id);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+package_py_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *v;
+ DnfPackage *self_package, *other_package;
+
+ if (!package_converter(self, &self_package) ||
+ !package_converter(other, &other_package)) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ long result = dnf_package_cmp(self_package, other_package);
+
+ switch (op) {
+ case Py_EQ:
+ v = TEST_COND(result == 0);
+ break;
+ case Py_NE:
+ v = TEST_COND(result != 0);
+ break;
+ case Py_LE:
+ v = TEST_COND(result <= 0);
+ break;
+ case Py_GE:
+ v = TEST_COND(result >= 0);
+ break;
+ case Py_LT:
+ v = TEST_COND(result < 0);
+ break;
+ case Py_GT:
+ v = TEST_COND(result > 0);
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+ Py_INCREF(v);
+ return v;
+} CATCH_TO_PYTHON
+
+static PyObject *
+package_repr(_PackageObject *self) try
+{
+ DnfPackage *pkg = self->package;
+ const char *nevra = dnf_package_get_nevra(pkg);
+ PyObject *repr;
+
+ repr = PyString_FromFormat("<hawkey.Package object id %ld, %s, %s>",
+ package_hash(self), nevra,
+ dnf_package_get_reponame(pkg));
+ return repr;
+} CATCH_TO_PYTHON
+
+static PyObject *
+package_str(_PackageObject *self) try
+{
+ const char *cstr = dnf_package_get_nevra(self->package);
+ PyObject *ret = PyString_FromString(cstr);
+ return ret;
+} CATCH_TO_PYTHON
+
+long package_hash(_PackageObject *self) try
+{
+ return dnf_package_get_id(self->package);
+} CATCH_TO_PYTHON_INT
+
+/* getsetters */
+
+static PyObject *
+get_bool(_PackageObject *self, void *closure) try
+{
+ unsigned long (*func)(DnfPackage*);
+ func = (unsigned long (*)(DnfPackage*))closure;
+ return PyBool_FromLong(func(self->package));
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_num(_PackageObject *self, void *closure) try
+{
+ guint64 (*func)(DnfPackage*);
+ func = (guint64 (*)(DnfPackage*))closure;
+ return PyLong_FromUnsignedLongLong(func(self->package));
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_reldep(_PackageObject *self, void *closure) try
+{
+ DnfReldepList *(*func)(DnfPackage*) = (DnfReldepList *(*)(DnfPackage*))closure;
+ std::unique_ptr<DnfReldepList> reldeplist(func(self->package));
+ assert(reldeplist);
+ PyObject *list = reldeplist_to_pylist(reldeplist.get(), self->sack);
+
+ return list;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_str(_PackageObject *self, void *closure) try
+{
+ const char *(*func)(DnfPackage*);
+ const char *cstr;
+
+ func = (const char *(*)(DnfPackage*))closure;
+ cstr = func(self->package);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_str_array(_PackageObject *self, void *closure) try
+{
+ gchar ** (*func)(DnfPackage*);
+ gchar ** strv;
+
+ func = (gchar **(*)(DnfPackage*))closure;
+ strv = func(self->package);
+ PyObject *list = strlist_to_pylist((const char **)strv);
+ g_strfreev(strv);
+
+ return list;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_chksum(_PackageObject *self, void *closure) try
+{
+ HyChecksum *(*func)(DnfPackage*, int *);
+ int type;
+ HyChecksum *cs;
+
+ func = (HyChecksum *(*)(DnfPackage*, int *))closure;
+ cs = func(self->package, &type);
+ if (cs == 0) {
+ Py_RETURN_NONE;
+ }
+
+ PyObject *res;
+ int checksum_length = checksum_type2length(type);
+
+#if PY_MAJOR_VERSION < 3
+ res = Py_BuildValue("is#", type, cs, checksum_length);
+#else
+ res = Py_BuildValue("iy#", type, cs, (Py_ssize_t)checksum_length);
+#endif
+
+ return res;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_changelogs(_PackageObject *self, void *closure) try
+{
+ return changelogslist_to_pylist(dnf_package_get_changelogs(self->package));
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_local_baseurl(_PackageObject *self) try
+{
+ g_autoptr(GError) error = nullptr;
+ gchar *local_baseurl = dnf_package_get_local_baseurl(self->package, &error);
+
+ if (error != nullptr) {
+ op_error2exc(error);
+ return nullptr;
+ }
+
+ if (local_baseurl == nullptr) {
+ return nullptr;
+ }
+
+ PyObject *ret = PyString_FromString(local_baseurl);
+ g_free(local_baseurl);
+ return ret;
+} CATCH_TO_PYTHON
+
+static PyGetSetDef package_getsetters[] = {
+ {(char*)"baseurl", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_baseurl},
+ {(char*)"files", (getter)get_str_array, NULL, NULL,
+ (void *)dnf_package_get_files},
+ {(char*)"changelogs", (getter)get_changelogs, NULL, NULL, NULL},
+ {(char*)"hdr_end", (getter)get_num, NULL, NULL, (void *)dnf_package_get_hdr_end},
+ {(char*)"location", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_location},
+ {(char*)"sourcerpm", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_sourcerpm},
+ {(char*)"version", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_version},
+ {(char*)"release", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_release},
+ {(char*)"name", (getter)get_str, NULL, NULL, (void *)dnf_package_get_name},
+ {(char*)"vendor", (getter)get_str, NULL, NULL, (void *)dnf_package_get_vendor},
+ {(char*)"arch", (getter)get_str, NULL, NULL, (void *)dnf_package_get_arch},
+ {(char*)"hdr_chksum", (getter)get_chksum, NULL, NULL,
+ (void *)dnf_package_get_hdr_chksum},
+ {(char*)"chksum", (getter)get_chksum, NULL, NULL, (void *)dnf_package_get_chksum},
+ {(char*)"description", (getter)get_str, NULL, NULL,
+ (void *)dnf_package_get_description},
+ {(char*)"evr", (getter)get_str, NULL, NULL, (void *)dnf_package_get_evr},
+ {(char*)"group", (getter)get_str, NULL, NULL, (void *)dnf_package_get_group},
+ {(char*)"license", (getter)get_str, NULL, NULL, (void *)dnf_package_get_license},
+ {(char*)"packager", (getter)get_str, NULL, NULL, (void *)dnf_package_get_packager},
+ {(char*)"reponame", (getter)get_str, NULL, NULL, (void *)dnf_package_get_reponame},
+ {(char*)"summary", (getter)get_str, NULL, NULL, (void *)dnf_package_get_summary},
+ {(char*)"url", (getter)get_str, NULL, NULL, (void *)dnf_package_get_url},
+ {(char*)"downloadsize", (getter)get_num, NULL, NULL,
+ (void *)dnf_package_get_downloadsize},
+ {(char*)"epoch", (getter)get_num, NULL, NULL, (void *)dnf_package_get_epoch},
+ {(char*)"installsize", (getter)get_num, NULL, NULL,
+ (void *)dnf_package_get_installsize},
+ {(char*)"buildtime", (getter)get_num, NULL, NULL, (void *)dnf_package_get_buildtime},
+ {(char*)"installtime", (getter)get_num, NULL, NULL,
+ (void *)dnf_package_get_installtime},
+ {(char*)"installed", (getter)get_bool, NULL, NULL, (void *)dnf_package_installed},
+ {(char*)"medianr", (getter)get_num, NULL, NULL, (void *)dnf_package_get_medianr},
+ {(char*)"rpmdbid", (getter)get_num, NULL, NULL, (void *)dnf_package_get_rpmdbid},
+ {(char*)"size", (getter)get_num, NULL, NULL, (void *)dnf_package_get_size},
+ {(char*)"conflicts", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_conflicts},
+ {(char*)"enhances", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_enhances},
+ {(char*)"obsoletes", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_obsoletes},
+ {(char*)"requires_pre", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_requires_pre},
+ {(char*)"provides", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_provides},
+ {(char*)"recommends", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_recommends},
+ {(char*)"requires", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_requires},
+ {(char*)"suggests", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_suggests},
+ {(char*)"supplements", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_supplements},
+ {(char*)"prereq_ignoreinst", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_prereq_ignoreinst},
+ {(char*)"regular_requires", (getter)get_reldep, NULL, NULL,
+ (void *)dnf_package_get_regular_requires},
+ {NULL} /* sentinel */
+};
+
+/* object methods */
+
+static PyObject *
+evr_cmp(_PackageObject *self, PyObject *other) try
+{
+ DnfPackage *pkg2 = packageFromPyObject(other);
+ if (pkg2 == NULL)
+ return NULL;
+ return PyLong_FromLong(dnf_package_evr_cmp(self->package, pkg2));
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_delta_from_evr(_PackageObject *self, PyObject *evr_str) try
+{
+ PycompString evr(evr_str);
+ if (!evr.getCString())
+ return NULL;
+ DnfPackageDelta *delta_c = dnf_package_get_delta_from_evr(self->package, evr.getCString());
+ if (delta_c)
+ return packageDeltaToPyObject(delta_c);
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+is_in_active_module(_PackageObject *self, PyObject *unused) try
+{
+ DnfSack * csack = sackFromPyObject(self->sack);
+ std::unique_ptr<DnfPackageSet> includes(dnf_sack_get_module_includes(csack));
+ if (!includes) {
+ Py_RETURN_FALSE;
+ }
+ if (includes->has(dnf_package_get_id(self->package))) {
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_advisories(_PackageObject *self, PyObject *args) try
+{
+ int cmp_type;
+ GPtrArray *advisories;
+ PyObject *list;
+
+ if (!PyArg_ParseTuple(args, "i", &cmp_type))
+ return NULL;
+
+ advisories = dnf_package_get_advisories(self->package, cmp_type);
+ list = advisorylist_to_pylist(advisories, self->sack);
+ g_ptr_array_unref(advisories);
+
+ return list;
+} CATCH_TO_PYTHON
+
+
+static struct PyMethodDef package_methods[] = {
+ {"evr_cmp", (PyCFunction)evr_cmp, METH_O, NULL},
+ {"get_delta_from_evr", (PyCFunction)get_delta_from_evr, METH_O, NULL},
+ {"get_advisories", (PyCFunction)get_advisories, METH_VARARGS, NULL},
+ {"_is_in_active_module", (PyCFunction)is_in_active_module, METH_NOARGS, NULL},
+ {"get_local_baseurl", (PyCFunction)get_local_baseurl, METH_NOARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject package_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Package", /*tp_name*/
+ sizeof(_PackageObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) package_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)package_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ (hashfunc)package_hash, /*tp_hash */
+ 0, /*tp_call*/
+ (reprfunc)package_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Package object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc) package_py_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ package_methods, /* tp_methods */
+ 0, /* tp_members */
+ package_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)package_init, /* tp_init */
+ 0, /* tp_alloc */
+ package_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PACKAGE_PY_H
+#define PACKAGE_PY_H
+
+#include "hy-types.h"
+
+extern PyTypeObject package_Type;
+
+DnfPackage *packageFromPyObject(PyObject *o);
+int package_converter(PyObject *o, DnfPackage **pkg_ptr);
+
+#endif // PACKAGE_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+// hawkey
+#include "hy-iutil.h"
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "packagedelta-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfPackageDelta *delta;
+} _PackageDeltaObject;
+
+PyObject *
+packageDeltaToPyObject(DnfPackageDelta *delta)
+{
+ _PackageDeltaObject *self = PyObject_New(_PackageDeltaObject, &packageDelta_Type);
+ self->delta = delta;
+ return (PyObject *)self;
+}
+
+/* functions on the type */
+
+static void
+packageDelta_dealloc(_PackageDeltaObject *self)
+{
+ g_object_unref(self->delta);
+ Py_TYPE(self)->tp_free(self);
+}
+
+/* getsetters */
+
+static PyObject *
+get_str(_PackageDeltaObject *self, void *closure) try
+{
+ const char *(*func)(DnfPackageDelta *);
+ const char *cstr;
+
+ func = (const char *(*)(DnfPackageDelta *))closure;
+ cstr = func(self->delta);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyString_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_num(_PackageDeltaObject *self, void *closure) try
+{
+ guint64 (*func)(DnfPackageDelta *);
+ func = (guint64 (*)(DnfPackageDelta *))closure;
+ return PyLong_FromUnsignedLongLong(func(self->delta));
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_chksum(_PackageDeltaObject *self, void *closure) try
+{
+ HyChecksum *(*func)(DnfPackageDelta *, int *);
+ int type;
+ HyChecksum *cs;
+
+ func = (HyChecksum *(*)(DnfPackageDelta *, int *))closure;
+ cs = func(self->delta, &type);
+ if (cs == 0) {
+ Py_RETURN_NONE;
+ }
+
+ PyObject *res;
+ int checksum_length = checksum_type2length(type);
+
+#if PY_MAJOR_VERSION < 3
+ res = Py_BuildValue("is#", type, cs, checksum_length);
+#else
+ res = Py_BuildValue("iy#", type, cs, (Py_ssize_t)checksum_length);
+#endif
+
+ return res;
+} CATCH_TO_PYTHON
+
+static PyGetSetDef packageDelta_getsetters[] = {
+ {(char*) "location", (getter)get_str, NULL, NULL,
+ (void *)dnf_packagedelta_get_location},
+ {(char*) "baseurl", (getter)get_str, NULL, NULL,
+ (void *)dnf_packagedelta_get_baseurl},
+ {(char*) "downloadsize", (getter)get_num, NULL, NULL,
+ (void *)dnf_packagedelta_get_downloadsize},
+ {(char*) "chksum", (getter)get_chksum, NULL, NULL,
+ (void *)dnf_packagedelta_get_chksum},
+ {NULL} /* sentinel */
+};
+
+/* type */
+
+PyTypeObject packageDelta_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.PackageDelta", /*tp_name*/
+ sizeof(_PackageDeltaObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) packageDelta_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "PackageDelta object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ packageDelta_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PACKAGEDELTA_PY_H
+#define PACKAGEDELTA_PY_H
+
+#include "hy-types.h"
+
+extern PyTypeObject packageDelta_Type;
+
+PyObject *packageDeltaToPyObject(DnfPackageDelta *delta);
+
+#endif // PACKAGEDELTA_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+#include "pycomp.hpp"
+
+/**
+ * unicode string in Python 2/3 to c string converter,
+ * you need to call Py_XDECREF(tmp_py_str) after usage of returned string
+ */
+static char *
+pycomp_get_string_from_unicode(PyObject *str_u, PyObject **tmp_py_str)
+{
+ *tmp_py_str = PyUnicode_AsEncodedString(str_u, "utf-8", "replace");
+ if (*tmp_py_str) {
+ return PyBytes_AsString(*tmp_py_str);
+ } else {
+ return NULL;
+ }
+}
+
+PycompString::PycompString(PyObject * str)
+{
+ if (PyUnicode_Check(str)) {
+ PyObject * pyString;
+ auto cString = pycomp_get_string_from_unicode(str, &pyString);
+ if (cString) {
+ cppString = cString;
+ isNull = false;
+ }
+ Py_XDECREF(pyString);
+#if PY_MAJOR_VERSION < 3
+ } else if (PyString_Check(str)) {
+ auto cString = PyString_AsString(str);
+ if (cString) {
+ cppString = cString;
+ isNull = false;
+ }
+ } else
+ PyErr_SetString(PyExc_TypeError, "Expected a string or a unicode object");
+#else
+ } else if (PyBytes_Check(str)) {
+ auto cString = PyBytes_AsString(str);
+ if (cString) {
+ cppString = cString;
+ isNull = false;
+ }
+ } else
+ PyErr_SetString(PyExc_TypeError, "Expected a string or a unicode object");
+#endif
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* module for Python 2/3 C API compatibility */
+
+#ifndef PYCOMP_H
+#define PYCOMP_H
+
+// Python 3 and newer types compatibility
+#if PY_MAJOR_VERSION >= 3
+ #define PyInt_Check PyLong_Check
+ #define PyString_FromString PyUnicode_FromString
+ #define PyString_FromFormat PyUnicode_FromFormat
+ #define PyString_Check PyBytes_Check
+ #define Py_TPFLAGS_HAVE_ITER 0
+#endif
+
+// uniform way to define Python 2 and Python 3 modules
+#if PY_MAJOR_VERSION >= 3
+ #define PYCOMP_MOD_ERROR_VAL NULL
+ #define PYCOMP_MOD_SUCCESS_VAL(val) val
+ #define PYCOMP_MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+ #define PYCOMP_MOD_DEF(ob, name, methods) \
+ static struct PyModuleDef moduledef = { \
+ PyModuleDef_HEAD_INIT, name, NULL, -1, methods, }; \
+ ob = PyModule_Create(&moduledef);
+#else
+ #define PYCOMP_MOD_ERROR_VAL
+ #define PYCOMP_MOD_SUCCESS_VAL(val)
+ #define PYCOMP_MOD_INIT(name) extern "C" void init##name(void)
+ #define PYCOMP_MOD_DEF(ob, name, methods) \
+ ob = Py_InitModule(name, methods);
+#endif
+
+
+// Python 2.5 and older compatibility
+#ifndef PyVarObject_HEAD_INIT
+ #define PyVarObject_HEAD_INIT(type, size) \
+ PyObject_HEAD_INIT(type) size,
+#endif
+
+#include <string>
+
+/**
+* @brief bytes, basic string or unicode string in Python 2/3 to c string converter
+*/
+class PycompString {
+public:
+ PycompString() = default;
+ explicit PycompString(PyObject * str);
+ const std::string & getString() const noexcept { return cppString; }
+ const char * getCString() const noexcept { return isNull ? nullptr : cppString.c_str(); }
+private:
+ bool isNull{true};
+ std::string cppString;
+};
+
+PYCOMP_MOD_INIT(_hawkey);
+
+#endif // PYCOMP_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+#include <solv/poolid.h>
+#include <solv/solver.h>
+#include <solv/util.h>
+#include <time.h>
+
+#include "error.hpp"
+#include "nevra.hpp"
+#include "hy-query-private.hpp"
+#include "hy-selector.h"
+#include "hy-subject.h"
+#include "dnf-reldep.h"
+#include "dnf-reldep-list.h"
+#include "repo/solvable/DependencyContainer.hpp"
+#include "transaction/Swdb.hpp"
+
+#include "exception-py.hpp"
+#include "hawkey-pysys.hpp"
+#include "iutil-py.hpp"
+#include "package-py.hpp"
+#include "query-py.hpp"
+#include "reldep-py.hpp"
+#include "sack-py.hpp"
+#include "pycomp.hpp"
+#include "sack/advisorypkg.hpp"
+#include "sack/packageset.hpp"
+#include "sack/selector.hpp"
+
+#include <algorithm>
+#include <functional>
+
+typedef struct {
+ PyObject_HEAD
+ HyQuery query;
+ PyObject *sack;
+} _QueryObject;
+
+static const int keyname_int_matches[] = {
+ HY_PKG,
+ HY_PKG_ADVISORY,
+ HY_PKG_ADVISORY_BUG,
+ HY_PKG_ADVISORY_CVE,
+ HY_PKG_ADVISORY_SEVERITY,
+ HY_PKG_ADVISORY_TYPE,
+ HY_PKG_ARCH,
+ HY_PKG_CONFLICTS,
+ HY_PKG_DESCRIPTION,
+ HY_PKG_DOWNGRADABLE,
+ HY_PKG_DOWNGRADES,
+ HY_PKG_EMPTY,
+ HY_PKG_ENHANCES,
+ HY_PKG_EPOCH,
+ HY_PKG_EVR,
+ HY_PKG_FILE,
+ HY_PKG_LATEST,
+ HY_PKG_LATEST_PER_ARCH,
+ HY_PKG_LATEST_PER_ARCH_BY_PRIORITY,
+ HY_PKG_LOCATION,
+ HY_PKG_NAME,
+ HY_PKG_NEVRA,
+ HY_PKG_NEVRA_STRICT,
+ HY_PKG_OBSOLETES,
+ HY_PKG_OBSOLETES_BY_PRIORITY,
+ HY_PKG_PROVIDES,
+ HY_PKG_RECOMMENDS,
+ HY_PKG_RELEASE,
+ HY_PKG_REPONAME,
+ HY_PKG_REQUIRES,
+ HY_PKG_SOURCERPM,
+ HY_PKG_SUGGESTS,
+ HY_PKG_SUMMARY,
+ HY_PKG_SUPPLEMENTS,
+ HY_PKG_UPGRADABLE,
+ HY_PKG_UPGRADES,
+ HY_PKG_UPGRADES_BY_PRIORITY,
+ HY_PKG_URL,
+ HY_PKG_VERSION
+};
+
+static const char * const keyname_char_matches[] = {
+ "pkg",
+ "advisory",
+ "advisory_bug",
+ "advisory_cve",
+ "advisory_severity",
+ "advisory_type",
+ "arch",
+ "conflicts",
+ "description",
+ "downgradable",
+ "downgrades",
+ "empty",
+ "enhances",
+ "epoch",
+ "evr",
+ "file",
+ "latest",
+ "latest_per_arch",
+ "latest_per_arch_by_priority",
+ "location",
+ "name",
+ "nevra",
+ "nevra_strict",
+ "obsoletes",
+ "obsoletes_by_priority",
+ "provides",
+ "recommends",
+ "release",
+ "reponame",
+ "requires",
+ "sourcerpm",
+ "suggests",
+ "summary",
+ "supplements",
+ "upgradable",
+ "upgrades",
+ "upgrades_by_priority",
+ "url",
+ "version",
+ NULL
+};
+
+static const char * const query_cmp_map_char[] = {
+ "eq",
+ "gt",
+ "lt",
+ "neq",
+ "not",
+ "gte",
+ "lte",
+ "substr",
+ "glob",
+ "eqg",
+ "upgrade",
+ NULL
+};
+
+static const int query_cmp_map_int[] = {
+ HY_EQ,
+ HY_GT,
+ HY_LT,
+ HY_NEQ,
+ HY_NOT,
+ HY_EQ | HY_GT,
+ HY_EQ | HY_LT,
+ HY_SUBSTR,
+ HY_GLOB,
+ HY_EQG,
+ HY_UPGRADE
+};
+
+HyQuery
+queryFromPyObject(PyObject *o)
+{
+ if (!PyType_IsSubtype(o->ob_type, &query_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a Query object.");
+ return NULL;
+ }
+ return ((_QueryObject *)o)->query;
+}
+
+PyObject *
+queryToPyObject(HyQuery query, PyObject *sack, PyTypeObject *custom_object_type)
+{
+ _QueryObject *self = (_QueryObject *)custom_object_type->tp_alloc(custom_object_type, 0);
+ if (self) {
+ self->query = query;
+ self->sack = sack;
+ Py_INCREF(sack);
+ }
+ return (PyObject *) self;
+}
+
+int
+query_converter(PyObject *o, HyQuery *query_ptr)
+{
+ HyQuery query = queryFromPyObject(o);
+ if (query == NULL)
+ return 0;
+ *query_ptr = query;
+ return 1;
+}
+
+/* functions on the type */
+
+static PyObject *
+query_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _QueryObject *self = (_QueryObject *)type->tp_alloc(type, 0);
+ if (self) {
+ self->query = NULL;
+ self->sack = NULL;
+ }
+ return (PyObject *)self;
+} CATCH_TO_PYTHON
+
+static void
+query_dealloc(_QueryObject *self)
+{
+ if (self->query)
+ delete self->query;
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+query_init(_QueryObject * self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"sack", "flags", "query", NULL};
+ PyObject *sack = NULL;
+ PyObject *query = NULL;
+ int flags = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OiO", (char**) kwlist, &sack, &flags, &query))
+ return -1;
+
+ if (query && (!sack || sack == Py_None) && queryObject_Check(query)) {
+ _QueryObject *query_obj = (_QueryObject*)query;
+ self->sack = query_obj->sack;
+ self->query = new libdnf::Query(*query_obj->query);
+ } else if (sack && (!query || query == Py_None) && sackObject_Check(sack)) {
+ DnfSack *csack = sackFromPyObject(sack);
+ assert(csack);
+ self->sack = sack;
+ self->query = new libdnf::Query(csack, static_cast<libdnf::Query::ExcludeFlags>(flags));
+ } else {
+ const char *msg = "Expected a _hawkey.Sack or a _hawkey.Query object.";
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+ Py_INCREF(self->sack);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+/* object attributes */
+
+static PyObject *
+get_evaluated(_QueryObject *self, void *unused) try
+{
+ HyQuery q = self->query;
+ return PyBool_FromLong((long) q->getApplied());
+} CATCH_TO_PYTHON
+
+static PyObject *
+clear(_QueryObject *self, PyObject *unused) try
+{
+ self->query->clear();
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static int
+raise_bad_filter(void)
+{
+ PyErr_SetString(HyExc_Query, "Invalid filter key or match type.");
+ return 0;
+}
+
+static int
+filter_add(HyQuery query, key_t keyname, int cmp_type, PyObject *match)
+{
+ if (keyname == HY_PKG_DOWNGRADABLE ||
+ keyname == HY_PKG_DOWNGRADES ||
+ keyname == HY_PKG_EMPTY ||
+ keyname == HY_PKG_LATEST_PER_ARCH ||
+ keyname == HY_PKG_LATEST_PER_ARCH_BY_PRIORITY ||
+ keyname == HY_PKG_LATEST ||
+ keyname == HY_PKG_UPGRADABLE ||
+ keyname == HY_PKG_UPGRADES ||
+ keyname == HY_PKG_UPGRADES_BY_PRIORITY) {
+ int val;
+
+ if (!PyInt_Check(match) || cmp_type != HY_EQ) {
+ PyErr_SetString(HyExc_Value, "Invalid boolean filter query.");
+ return 0;
+ }
+ long val_long = PyLong_AsLong(match);
+ if (val_long < INT_MIN) {
+ val = INT_MIN;
+ } else if (val_long > INT_MAX) {
+ val = INT_MAX;
+ } else {
+ val = val_long;
+ }
+ if (keyname == HY_PKG_EMPTY) {
+ if (!val) {
+ PyErr_SetString(HyExc_Value, "Invalid boolean filter query.");
+ return 0;
+ }
+ query->addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+ } else {
+ query->addFilter(keyname, HY_EQ, val);
+ }
+ return 1;
+ }
+ if (PyUnicode_Check(match) || PyString_Check(match)) {
+ PycompString cmatch(match);
+ if (!cmatch.getCString())
+ return 0;
+ int query_filter_ret = query->addFilter(keyname, cmp_type, cmatch.getCString());
+
+ if (query_filter_ret)
+ return raise_bad_filter();
+ return 1;
+ }
+ if (PyInt_Check(match)) {
+ long val = PyLong_AsLong(match);
+ if (cmp_type == HY_GLOB) // Workaround: Python can send integer with HY_GLOB
+ cmp_type = HY_EQ;
+ if (val > INT_MAX || val < INT_MIN) {
+ PyErr_SetString(HyExc_Value, "Numeric argument out of range.");
+ return 0;
+ }
+ if (query->addFilter(keyname, cmp_type, val))
+ return raise_bad_filter();
+ return 1;
+ }
+ if (queryObject_Check(match)) {
+ HyQuery target = queryFromPyObject(match);
+ const DnfPackageSet * pset = target->runSet();
+ int ret = query->addFilter(keyname, cmp_type, pset);
+
+ if (ret)
+ return raise_bad_filter();
+ return 1;
+ }
+ if (reldepObject_Check(match)) {
+ DnfReldep *reldep = reldepFromPyObject(match);
+
+ /* A reldep cannot be used across sack objects. If there is an attempt
+ * to do so, the underlying libsolv structures are incomplete and a SEGFAULT is
+ * likely to occur. */
+
+ if (query->getSack() != reldep->getSack()) {
+ PyErr_SetString(HyExc_Query, "Direct dependency lookups must originate from the same sack.");
+ return 0;
+ }
+
+ if (cmp_type != HY_EQ || query->addFilter(keyname, reldep))
+ return raise_bad_filter();
+ return 1;
+ }
+ // match is a sequence now:
+ switch (keyname) {
+ case HY_PKG:
+ case HY_PKG_OBSOLETES:
+ case HY_PKG_OBSOLETES_BY_PRIORITY:
+ case HY_PKG_CONFLICTS:
+ case HY_PKG_REQUIRES:
+ case HY_PKG_ENHANCES:
+ case HY_PKG_RECOMMENDS:
+ case HY_PKG_SUGGESTS:
+ case HY_PKG_SUPPLEMENTS: {
+ // It could be a sequence of packages or reldep/strings. Lets try packages first.
+ auto pset = pyseq_to_packageset(match, query->getSack());
+ if (!pset) {
+ if (auto PyError = PyErr_Occurred()) {
+ // It was not a sequence of packages.
+ if (PyErr_GivenExceptionMatches(PyError, PyExc_TypeError)) {
+ PyErr_Clear();
+ auto reldeplist = pyseq_to_reldeplist(match, query->getSack(), cmp_type);
+ if (reldeplist == NULL)
+ return 1;
+
+ int ret = query->addFilter(keyname, reldeplist.get());
+ if (ret) {
+ return raise_bad_filter();
+ }
+ break;
+ }
+ }
+ return 1;
+ }
+ int ret = query->addFilter(keyname, cmp_type, pset.get());
+ if (ret)
+ return raise_bad_filter();
+
+ break;
+ }
+ case HY_PKG_PROVIDES: {
+ auto reldeplist = pyseq_to_reldeplist(match, query->getSack(), cmp_type);
+ if (reldeplist == NULL)
+ return 1;
+
+ int ret = query->addFilter(keyname, reldeplist.get());
+ if (ret)
+ return raise_bad_filter();
+ break;
+ }
+ default: {
+ std::vector<std::string> matches;
+ try {
+ matches = pySequenceConverter(match);
+ } catch (std::runtime_error &) {
+ return 0;
+ }
+ std::vector<const char *> matchesCString(matches.size() + 1);
+ std::transform(matches.begin(), matches.end(), matchesCString.begin(),
+ std::mem_fn(&std::string::c_str));
+ int filter_in_ret = query->addFilter(keyname, cmp_type, matchesCString.data());
+ if (filter_in_ret)
+ return raise_bad_filter();
+ break;
+ }
+ }
+ return 1;
+}
+
+static char *
+filter_key_splitter(char** key)
+{
+ char *sbegin = *key;
+ char *end;
+
+ if (sbegin == NULL)
+ return NULL;
+ int index;
+
+ for (index = 0; sbegin[index] != '\0'; ++index) {
+ if ((sbegin[index] == '_') && (sbegin[index + 1] == '_')) {
+ end = sbegin + index;
+ *end++ = '\0';
+ *key = ++end;
+ return sbegin;
+ }
+ }
+ *key = NULL;
+ return sbegin;
+}
+
+gboolean
+filter_internal(HyQuery query, HySelector sltr, PyObject *sack, PyObject *args, PyObject *kwds)
+{
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+ key_t keyname;
+ int cmp_type;
+ PyObject *tuple_item;
+ int argument_number, presence_cmp_type;
+ int cmp_type_flag = 0;
+
+ if (args != NULL) {
+ Py_ssize_t tuple_size = PyTuple_Size(args);
+ for (int x = 0; x < tuple_size; ++x) {
+ tuple_item = PyTuple_GetItem(args, x);
+ if (PyInt_Check(tuple_item)) {
+ long c_int = PyLong_AsLong(tuple_item);
+ if (c_int == HY_ICASE) {
+ cmp_type_flag = HY_ICASE;
+ } else {
+ PyErr_SetString(HyExc_Value, "Invalid flag. Only HY_ICASE allowed");
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if (kwds != NULL) {
+ while (PyDict_Next(kwds, &pos, &key, &value)) {
+ keyname = -1;
+ argument_number = 0;
+ PycompString cmatch(key);
+ if (!cmatch.getCString())
+ return FALSE;
+ auto parsed_string = cmatch.getString();
+ char *tmp_string = &parsed_string.front();
+ cmp_type = 0;
+ char *parcial_string;
+ while ((parcial_string = filter_key_splitter(&tmp_string)) != NULL) {
+ if (!argument_number) {
+ for (unsigned int i = 0; keyname_char_matches[i] != NULL; ++i) {
+ if (strcmp(keyname_char_matches[i], parcial_string) == 0) {
+ keyname = keyname_int_matches[i];
+ argument_number = 1;
+ break;
+ }
+ }
+ if (!argument_number) {
+ PyErr_SetString(HyExc_Value, g_strdup_printf(
+ "Unrecognized key name: %s", parcial_string));
+ return FALSE;
+ }
+ } else {
+ presence_cmp_type = FALSE;
+ for (unsigned int i = 0; query_cmp_map_char[i] != NULL; ++i) {
+ if (strcmp(query_cmp_map_char[i], parcial_string) == 0) {
+ cmp_type |= query_cmp_map_int[i];
+ presence_cmp_type = TRUE;
+ break;
+ }
+ }
+ if (!presence_cmp_type) {
+ PyErr_SetString(HyExc_Value, g_strdup_printf(
+ "Unrecognized filter type: %s", parcial_string));
+ return FALSE;
+ }
+ }
+ }
+ if (cmp_type == 0) {
+ cmp_type = HY_EQ;
+ }
+ if (keyname != -1) {
+ if (query != NULL) {
+ if (filter_add(query, keyname, cmp_type|cmp_type_flag, value) == 0) {
+ return FALSE;
+ }
+ } else {
+ if (keyname == HY_PKG) {
+ DnfSack *c_sack = sackFromPyObject(sack);
+ assert(c_sack);
+ auto pset = pyseq_to_packageset(value, c_sack);
+ if (!pset) {
+ ret2e(DNF_ERROR_BAD_SELECTOR, "Invalid value type: Only List and Query supported");
+ return FALSE;
+ }
+ if (!sltr) {
+ PyErr_SetString(HyExc_Value, "Selector is nulptr");
+ return FALSE;
+ }
+ if (ret2e(sltr->set(pset.get()),
+ "Invalid Selector spec." )) {
+ return FALSE;
+ }
+ } else {
+ PycompString c_sltr_match(value);
+ if (!c_sltr_match.getCString())
+ return FALSE;
+ if (ret2e(hy_selector_set(sltr, keyname, cmp_type, c_sltr_match.getCString()),
+ "Invalid Selector spec." )) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+static PyObject *
+filter(_QueryObject *self, PyObject *args, PyObject *kwds) try {
+ auto query = std::unique_ptr<libdnf::Query>(new libdnf::Query(*self->query));
+ gboolean ret = filter_internal(query.get(), NULL, self->sack, args, kwds);
+ if (!ret)
+ return NULL;
+ PyObject *final_query = queryToPyObject(query.release(), self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static _QueryObject *
+filterm(_QueryObject *self, PyObject *args, PyObject *kwds) try {
+ gboolean ret = filter_internal(self->query, NULL, self->sack, args, kwds);
+ if (!ret)
+ return NULL;
+ Py_INCREF(self);
+ return self;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_available_filter(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = new libdnf::Query(*self->query);
+ query->available();
+ PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_downgrades_filter(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = new libdnf::Query(*self->query);
+ query->addFilter(HY_PKG_DOWNGRADES, HY_EQ, 1);
+ PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+duplicated_filter(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery self_query_copy = new libdnf::Query(*self->query);
+ self_query_copy->filterDuplicated();
+ PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_filter_extras(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery self_query_copy = new libdnf::Query(*self->query);
+ self_query_copy->filterExtras();
+ PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_installed_filter(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = new libdnf::Query(*self->query);
+ query->installed();
+ PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_filter_latest(_QueryObject *self, PyObject *args) try
+{
+ int value = 1;
+
+ if (!PyArg_ParseTuple(args, "|i", &value))
+ return NULL;
+
+ HyQuery query = new libdnf::Query(*self->query);
+ query->addFilter(HY_PKG_LATEST_PER_ARCH, HY_EQ, value);
+ PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_upgrades_filter(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = new libdnf::Query(*self->query);
+ query->addFilter(HY_PKG_UPGRADES, HY_EQ, 1);
+ PyObject *final_query = queryToPyObject(query, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+
+static PyObject *
+run(_QueryObject *self, PyObject *unused) try
+{
+ PyObject *list;
+
+ const DnfPackageSet * pset = self->query->runSet();
+ list = packageset_to_pylist(pset, self->sack);
+ return list;
+} CATCH_TO_PYTHON
+
+static PyObject *
+apply(PyObject *self, PyObject *unused) try
+{
+ ((_QueryObject *) self)->query->apply();
+ Py_INCREF(self);
+ return self;
+} CATCH_TO_PYTHON
+
+static PyObject *
+q_union(PyObject *self, PyObject *args) try
+{
+ PyObject *other;
+ if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
+ return NULL;
+
+ HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
+ HyQuery other_q = ((_QueryObject *) other)->query;
+ self_query_copy->queryUnion(*other_q);
+ PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
+ Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+q_intersection(PyObject *self, PyObject *args) try
+{
+ PyObject *other;
+ if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
+ return NULL;
+
+ HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
+ HyQuery other_q = ((_QueryObject *) other)->query;
+ self_query_copy->queryIntersection(*other_q);
+ PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
+ Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+q_difference(PyObject *self, PyObject *args) try
+{
+ PyObject *other;
+ if (!PyArg_ParseTuple(args, "O!", &query_Type, &other))
+ return NULL;
+
+ HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
+ HyQuery other_q = ((_QueryObject *) other)->query;
+ self_query_copy->queryDifference(*other_q);
+ PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
+ Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+typedef struct {
+ PyObject_HEAD
+ libdnf::Swdb *ptr;
+ void *ty;
+ int own;
+ PyObject *next;
+} SwdbSwigPyObject;
+
+static PyObject *
+get_advisory_pkgs(_QueryObject *self, PyObject *args) try
+{
+ int cmpType;
+
+ if (!PyArg_ParseTuple(args, "i", &cmpType))
+ return NULL;
+
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+
+ self->query->getAdvisoryPkgs(cmpType, advisoryPkgs);
+ return advisoryPkgVectorToPylist(advisoryPkgs);
+} CATCH_TO_PYTHON
+
+static PyObject *
+filter_userinstalled(PyObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"swdb", NULL};
+ PyObject *pySwdb;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &pySwdb)) {
+ return NULL;
+ }
+
+ UniquePtrPyObject thisPySwdb(PyObject_GetAttrString(pySwdb, "this"));
+ auto swigSwdb = reinterpret_cast< SwdbSwigPyObject * >(thisPySwdb.get());
+
+ if (swigSwdb == nullptr) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject");
+ return NULL;
+ }
+
+ libdnf::Swdb * swdb = swigSwdb->ptr;
+
+ if (swdb == NULL) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse swig object");
+ return NULL;
+ }
+ HyQuery self_query_copy = new libdnf::Query(*((_QueryObject *) self)->query);
+ self_query_copy->filterUserInstalled(*swdb);
+
+ PyObject *final_query = queryToPyObject(self_query_copy, ((_QueryObject *) self)->sack,
+ Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+filter_unneeded_or_safe_to_remove(PyObject *self, PyObject *args, PyObject *kwds, bool SafeToRemove)
+{
+ const char *kwlist[] = {"swdb", "debug_solver", NULL};
+ PyObject *pySwdb;
+ PyObject *debug_solver = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "O|O!", (char **)kwlist, &pySwdb, &PyBool_Type, &debug_solver)) {
+ return NULL;
+ }
+
+ UniquePtrPyObject thisPySwdb(PyObject_GetAttrString(pySwdb, "this"));
+ auto swigSwdb = reinterpret_cast< SwdbSwigPyObject * >(thisPySwdb.get());
+
+ if (swigSwdb == nullptr) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse SwigPyObject");
+ return NULL;
+ }
+
+ libdnf::Swdb *swdb = swigSwdb->ptr;
+
+ if (swdb == NULL) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse swig object");
+ return NULL;
+ }
+ std::unique_ptr<libdnf::Query> self_query_copy(new libdnf::Query(*((_QueryObject *) self)->query));
+ gboolean c_debug_solver = debug_solver != NULL && PyObject_IsTrue(debug_solver);
+
+ int ret;
+ if (SafeToRemove) {
+ ret = self_query_copy->filterSafeToRemove(*swdb, c_debug_solver);
+ } else {
+ ret = self_query_copy->filterUnneeded(*swdb, c_debug_solver);
+ }
+ if (ret == -1) {
+ PyErr_SetString(PyExc_SystemError, "Unable to provide query with unneded filter");
+ return NULL;
+ }
+
+ PyObject *final_query = queryToPyObject(self_query_copy.release(), ((_QueryObject *) self)->sack,
+ Py_TYPE(self));
+ return final_query;
+}
+
+static PyObject *
+filter_safe_to_remove(PyObject *self, PyObject *args, PyObject *kwds) try
+{
+ return filter_unneeded_or_safe_to_remove(self, args, kwds, true);
+} CATCH_TO_PYTHON
+
+
+static PyObject *
+filter_unneeded(PyObject *self, PyObject *args, PyObject *kwds) try
+{
+ return filter_unneeded_or_safe_to_remove(self, args, kwds, false);
+} CATCH_TO_PYTHON
+
+static PyObject *
+q_add(_QueryObject *self, PyObject *list) try
+{
+ if (!PyList_Check(list)) {
+ PyErr_SetString(PyExc_TypeError, "Only a list can be concatenated to a Query");
+ return NULL;
+ }
+ PyObject *unused = NULL;
+ PyObject *query_list = run(self, unused);
+
+ int list_count = PyList_Size(list);
+ for (int index = 0; index < list_count; ++index)
+ PyList_Append(query_list, PyList_GetItem(list, index));
+ return query_list;
+} CATCH_TO_PYTHON
+
+static int
+query_contains(PyObject *self, PyObject *pypkg) try
+{
+ HyQuery q = ((_QueryObject *) self)->query;
+ DnfPackage *pkg = packageFromPyObject(pypkg);
+
+ if (pkg) {
+ Id id = dnf_package_get_id(pkg);
+ q->apply();
+ if (MAPTST(q->getResult(), id))
+ return 1;
+ }
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static size_t
+query_len(PyObject *self) try
+{
+ HyQuery q = ((_QueryObject *) self)->query;
+ return q->size();
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+q_length(PyObject *self, PyObject *unused) try
+{
+ return PyLong_FromLong(query_len(self));
+} CATCH_TO_PYTHON
+
+static PyObject *
+query_get_item(PyObject *self, int index) try
+{
+ HyQuery query = ((_QueryObject *) self)->query;
+ Id id = query->getIndexItem(index);
+ if (id == -1) {
+ PyErr_SetString(PyExc_IndexError, "list index out of range");
+ return NULL;
+ }
+ PyObject *package = new_package(((_QueryObject *) self)->sack, id);
+ return package;
+} CATCH_TO_PYTHON
+
+static PyObject *
+query_iter(PyObject *self) try
+{
+ const DnfPackageSet * pset = ((_QueryObject *) self)->query->runSet();
+ UniquePtrPyObject list(packageset_to_pylist(pset, ((_QueryObject *) self)->sack));
+ if (!list)
+ return NULL;
+ PyObject *iter = PyObject_GetIter(list.get());
+ return iter;
+} CATCH_TO_PYTHON
+
+static PyObject *
+query_to_name_dict(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = ((_QueryObject *) self)->query;
+ Pool *pool = dnf_sack_get_pool(query->getSack());
+
+ libdnf::IdQueue samename;
+ hy_query_to_name_ordered_queue(query, &samename);
+
+ Solvable *considered;
+ Id name = 0;
+ UniquePtrPyObject list(PyList_New(0));
+ UniquePtrPyObject ret_dict(PyDict_New());
+
+ for (int i = 0; i < samename.size(); ++i) {
+ Id package_id = samename[i];
+ considered = pool->solvables + package_id;
+ if (name == 0) {
+ name = considered->name;
+ } else if (name != considered->name) {
+ PyDict_SetItemString(ret_dict.get(), pool_id2str(pool, name), list.get());
+ list.reset(PyList_New(0));
+ name = considered->name;
+ }
+ UniquePtrPyObject package(new_package(self->sack, package_id));
+ if (!package)
+ goto fail;
+
+ int rc = PyList_Append(list.get(), package.get());
+ if (rc == -1)
+ goto fail;
+ }
+ if (name)
+ PyDict_SetItemString(ret_dict.get(), pool_id2str(pool, name), list.get());
+ return ret_dict.release();
+
+ fail:
+ PyErr_SetString(PyExc_SystemError, "Unable to create name_dict");
+ return NULL;
+} CATCH_TO_PYTHON
+
+static PyObject *
+query_to_name_arch_dict(_QueryObject *self, PyObject *unused) try
+{
+ HyQuery query = ((_QueryObject *) self)->query;
+ Pool *pool = dnf_sack_get_pool(query->getSack());
+
+ libdnf::IdQueue samename;
+
+ hy_query_to_name_arch_ordered_queue(query, &samename);
+
+ Solvable *considered;
+ Id name = 0;
+ Id arch = 0;
+ UniquePtrPyObject key(PyTuple_New(2));
+ UniquePtrPyObject list(PyList_New(0));
+ UniquePtrPyObject ret_dict(PyDict_New());
+
+ for (int i = 0; i < samename.size(); ++i) {
+ Id package_id = samename[i];
+ considered = pool->solvables + package_id;
+ if (name == 0) {
+ name = considered->name;
+ arch = considered->arch;
+ } else if ((name != considered->name) || (arch != considered->arch)) {
+ if (PyTuple_SetItem(key.get(), 0, PyString_FromString(pool_id2str(pool, name))))
+ goto fail;
+ if (PyTuple_SetItem(key.get(), 1, PyString_FromString(pool_id2str(pool, arch))))
+ goto fail;
+ PyDict_SetItem(ret_dict.get(), key.get(), list.get());
+ key.reset(PyTuple_New(2));
+ list.reset(PyList_New(0));
+ name = considered->name;
+ arch = considered->arch;
+ }
+ UniquePtrPyObject package(new_package(self->sack, package_id));
+ if (!package)
+ goto fail;
+
+ int rc = PyList_Append(list.get(), package.get());
+ if (rc == -1)
+ goto fail;
+ }
+ if (name) {
+ if (PyTuple_SetItem(key.get(), 0, PyString_FromString(pool_id2str(pool, name))))
+ goto fail;
+ if (PyTuple_SetItem(key.get(), 1, PyString_FromString(pool_id2str(pool, arch))))
+ goto fail;
+ PyDict_SetItem(ret_dict.get(), key.get(), list.get());
+ }
+
+ return ret_dict.release();
+
+ fail:
+ PyErr_SetString(PyExc_SystemError, "Unable to create name_arch_dict");
+ return NULL;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_nevra_or_other_filter(_QueryObject *self, PyObject *args) try
+{
+ auto self_query_copy = std::unique_ptr<libdnf::Query>(new libdnf::Query(*self->query));
+
+ int arguments_count = PyTuple_Size(args);
+ if (arguments_count == 1) {
+ const char *name;
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return NULL;
+ libdnf::Nevra nevra;
+ if (nevra.parse(name, HY_FORM_NEVRA))
+ self_query_copy->addFilter(&nevra, false);
+ else
+ self_query_copy->addFilter(HY_PKG_EMPTY, HY_EQ, 1);
+ } else if (arguments_count == 3) {
+ const char *name;
+ const char *evr;
+ const char *arch;
+
+ if (!PyArg_ParseTuple(args, "sss", &name, &evr, &arch))
+ return NULL;
+ self_query_copy->addFilter(HY_PKG_NAME, HY_EQ, name);
+ self_query_copy->addFilter(HY_PKG_EVR, HY_EQ, evr);
+ self_query_copy->addFilter(HY_PKG_ARCH, HY_EQ, arch);
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "nevra() takes 1 (NEVRA), or 3 (name, evr, arch) str params");
+ return NULL;
+ }
+ PyObject *final_query = queryToPyObject(self_query_copy.release(), self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_filter_recent(_QueryObject *self, PyObject *args) try
+{
+ long recent;
+ if (!PyArg_ParseTuple(args, "l", &recent))
+ return NULL;
+
+ self->query->apply();
+ HyQuery self_query_copy = new libdnf::Query(*self->query);
+ time_t now = time(NULL);
+ time_t recent_limit = now - (recent*86400);
+ self_query_copy->filterRecent((recent_limit < 0) ? 0 : recent_limit);
+ PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self));
+ return final_query;
+} CATCH_TO_PYTHON
+
+static PyGetSetDef query_getsetters[] = {
+ {(char*)"evaluated", (getter)get_evaluated, NULL, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+PySequenceMethods query_sequence = {
+ (lenfunc)query_len, /* sq_length */
+ (binaryfunc)q_add, /* sq_concat */
+ 0, /* sq_repeat */
+ (ssizeargfunc) query_get_item, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ (objobjproc)query_contains, /* sq_contains */
+};
+
+static struct PyMethodDef query_methods[] = {
+ {"clear", (PyCFunction)clear, METH_NOARGS,
+ NULL},
+ {"filter", (PyCFunction)filter, METH_KEYWORDS|METH_VARARGS,
+ NULL},
+ {"filterm", (PyCFunction)filterm, METH_KEYWORDS|METH_VARARGS,
+ NULL},
+ {"run", (PyCFunction)run, METH_NOARGS,
+ NULL},
+ {"apply", (PyCFunction)apply, METH_NOARGS,
+ NULL},
+ {"available", (PyCFunction)add_available_filter, METH_NOARGS, NULL},
+ {"downgrades", (PyCFunction)add_downgrades_filter, METH_NOARGS, NULL},
+ {"duplicated", (PyCFunction)duplicated_filter, METH_NOARGS, NULL},
+ {"extras", (PyCFunction)add_filter_extras, METH_NOARGS, NULL},
+ {"installed", (PyCFunction)add_installed_filter, METH_NOARGS, NULL},
+ {"latest", (PyCFunction)add_filter_latest, METH_VARARGS, NULL},
+ {"union", (PyCFunction)q_union, METH_VARARGS, NULL},
+ {"upgrades", (PyCFunction)add_upgrades_filter, METH_NOARGS, NULL},
+ {"intersection", (PyCFunction)q_intersection, METH_VARARGS, NULL},
+ {"difference", (PyCFunction)q_difference, METH_VARARGS, NULL},
+ {"count", (PyCFunction)q_length, METH_NOARGS,
+ NULL},
+ {"get_advisory_pkgs", (PyCFunction)get_advisory_pkgs, METH_VARARGS, NULL},
+ {"userinstalled", (PyCFunction)filter_userinstalled, METH_KEYWORDS|METH_VARARGS, NULL},
+ {"_na_dict", (PyCFunction)query_to_name_arch_dict, METH_NOARGS, NULL},
+ {"_name_dict", (PyCFunction)query_to_name_dict, METH_NOARGS, NULL},
+ {"_nevra", (PyCFunction)add_nevra_or_other_filter, METH_VARARGS, NULL},
+ {"_recent", (PyCFunction)add_filter_recent, METH_VARARGS, NULL},
+ {"_unneeded", (PyCFunction)filter_unneeded, METH_KEYWORDS|METH_VARARGS, NULL},
+ {"_safe_to_remove", (PyCFunction)filter_safe_to_remove, METH_KEYWORDS|METH_VARARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject query_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Query", /*tp_name*/
+ sizeof(_QueryObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) query_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &query_sequence, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Query object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ query_iter, /* tp_iter */
+ 0, /* tp_iternext */
+ query_methods, /* tp_methods */
+ 0, /* tp_members */
+ query_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)query_init, /* tp_init */
+ 0, /* tp_alloc */
+ query_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef QUERY_PY_H
+#define QUERY_PY_H
+
+#include "hy-types.h"
+
+extern PyTypeObject query_Type;
+
+#define queryObject_Check(o) PyObject_TypeCheck(o, &query_Type)
+
+HyQuery queryFromPyObject(PyObject *o);
+PyObject *queryToPyObject(HyQuery query, PyObject *sack, PyTypeObject *custom_object_type);
+int query_converter(PyObject *o, HyQuery *query_ptr);
+gboolean filter_internal(HyQuery query, HySelector sltr, PyObject *sack, PyObject *args, PyObject *kwds);
+
+#endif // QUERY_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <Python.h>
+
+// libsolv
+#include <solv/util.h>
+
+// hawkey
+#include "dnf-reldep.h"
+#include "hy-iutil.h"
+#include "libdnf/repo/solvable/Dependency.hpp"
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "sack-py.hpp"
+#include "reldep-py.hpp"
+#include "iutil-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ DnfReldep *reldep;
+ PyObject *sack;
+} _ReldepObject;
+
+static _ReldepObject *
+reldep_new_core(PyTypeObject *type, PyObject *sack)
+{
+ _ReldepObject *self = (_ReldepObject*)type->tp_alloc(type, 0);
+ if (self == NULL)
+ return NULL;
+ self->reldep = NULL;
+ self->sack = sack;
+ Py_INCREF(self->sack);
+ return self;
+}
+
+PyObject *
+new_reldep(PyObject *sack, Id r_id)
+{
+ DnfSack *csack = sackFromPyObject(sack);
+ if (csack == NULL)
+ return NULL;
+
+ _ReldepObject *self = reldep_new_core(&reldep_Type, sack);
+ if (self == NULL)
+ return NULL;
+ self->reldep = new libdnf::Dependency(csack, r_id);
+ return (PyObject*)self;
+}
+
+DnfReldep *
+reldepFromPyObject(PyObject *o)
+{
+ if (!PyType_IsSubtype(o->ob_type, &reldep_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a Reldep object.");
+ return NULL;
+ }
+ return ((_ReldepObject*)o)->reldep;
+}
+
+static Id reldep_hash(_ReldepObject *self);
+
+static PyObject *
+reldep_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ PyObject *sack = PyTuple_GetItem(args, 0);
+ if (sack == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Expected a Sack object as the first argument.");
+ return NULL;
+ }
+ if (!sackObject_Check(sack)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected a Sack object as the first argument.");
+ return NULL;
+ }
+ return (PyObject *)reldep_new_core(type, sack);
+} CATCH_TO_PYTHON
+
+PyObject *
+reldepToPyObject(DnfReldep *reldep)
+{
+ _ReldepObject *self = (_ReldepObject *)reldep_Type.tp_alloc(&reldep_Type, 0);
+ if (self)
+ self->reldep = reldep;
+ return (PyObject *)self;
+}
+
+static int
+reldep_init(_ReldepObject *self, PyObject *args, PyObject *kwds) try
+{
+ PyObject *sack;
+ PyObject *reldep_str_py = NULL;
+ if (!PyArg_ParseTuple(args, "O!O", &sack_Type, &sack, &reldep_str_py))
+ return -1;
+ DnfSack *csack = sackFromPyObject(sack);
+ if (csack == NULL)
+ return -1;
+ PycompString reldep_str(reldep_str_py);
+ if (!reldep_str.getCString())
+ return -1;
+
+ try {
+ self->reldep = new libdnf::Dependency(csack, reldep_str.getCString());
+ }
+ catch (...) {
+ PyErr_Format(HyExc_Value, "Wrong reldep format: %s", reldep_str.getCString());
+ return -1;
+ }
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static void
+reldep_dealloc(_ReldepObject *self)
+{
+ if (self->reldep)
+ dnf_reldep_free(self->reldep);
+
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+reldep_repr(_ReldepObject *self) try
+{
+ long hash = reldep_hash(self);
+ if (PyErr_Occurred()) {
+ assert(hash == -1);
+ PyErr_Clear();
+ return PyString_FromString("<_hawkey.Reldep object, INVALID value>");
+ }
+ return PyString_FromFormat("<_hawkey.Reldep object, id: %lu>", hash);
+} CATCH_TO_PYTHON
+
+static PyObject *
+reldep_str(_ReldepObject *self) try
+{
+ DnfReldep *reldep = self->reldep;
+ const char *cstr = reldep->toString();
+ PyObject *retval = PyString_FromString(cstr);
+ return retval;
+} CATCH_TO_PYTHON
+
+static Id
+reldep_hash(_ReldepObject *self) try
+{
+ if (self->reldep == NULL) {
+ PyErr_SetString(HyExc_Value, "Invalid Reldep has no hash.");
+ return -1;
+ }
+ return self->reldep->getId();
+} CATCH_TO_PYTHON_INT
+
+static int
+reldep_converter(PyObject *o, DnfReldep **reldep_ptr)
+{
+ DnfReldep *reldep = reldepFromPyObject(o);
+ if (reldep == NULL)
+ return 0;
+ *reldep_ptr = reldep;
+ return 1;
+}
+
+static PyObject *
+reldep_richcompare(PyObject *self, PyObject *other, int op) try
+{
+ PyObject *result = NULL;
+ DnfReldep *cself, *cother;
+
+ if (!reldep_converter(self, &cself) ||
+ !reldep_converter(other, &cother)) {
+ if(PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError))
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ Id s_id = cself->getId();
+ Id o_id = cother->getId();
+ switch (op) {
+ case Py_EQ:
+ result = TEST_COND(s_id == o_id);
+ break;
+ case Py_NE:
+ result = TEST_COND(s_id != o_id);
+ break;
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ result = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ return result;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_str(_ReldepObject *self, void *closure) try
+{
+ const char *(*func)(DnfReldep*);
+ const char *cstr;
+
+ func = (const char *(*)(DnfReldep*))closure;
+ cstr = func(self->reldep);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static PyGetSetDef reldep_getsetters[] = {
+ {(char*)"name", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_name},
+ {(char*)"relation", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_relation},
+ {(char*)"version", (getter)get_str, NULL, NULL, (void *)dnf_reldep_get_version},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject reldep_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Reldep", /*tp_name*/
+ sizeof(_ReldepObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) reldep_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc)reldep_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ (hashfunc)reldep_hash, /*tp_hash */
+ 0, /*tp_call*/
+ (reprfunc)reldep_str, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Reldep object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)reldep_richcompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ reldep_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)reldep_init, /* tp_init */
+ 0, /* tp_alloc */
+ reldep_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RELDEP_PY_H
+#define RELDEP_PY_H
+
+// libsolv
+#include <solv/pooltypes.h>
+
+// hawkey
+#include "hy-types.h"
+
+extern PyTypeObject reldep_Type;
+
+#define reldepObject_Check(o) PyObject_TypeCheck(o, &reldep_Type)
+
+PyObject *new_reldep(PyObject *sack, Id r_id);
+DnfReldep *reldepFromPyObject(PyObject *o);
+PyObject *reldepToPyObject(DnfReldep *reldep);
+
+#endif // RELDEP_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+#include <stdint.h>
+
+// hawkey
+#include "hy-repo.h"
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "hawkey-pysys.hpp"
+#include "repo-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ HyRepo repo;
+} _RepoObject;
+
+typedef struct {
+ int (*getter)(HyRepo);
+ void (*setter)(HyRepo, int);
+} IntGetSetter;
+
+HyRepo repoFromPyObject(PyObject *o)
+{
+ if (!PyObject_TypeCheck(o, &repo_Type)) {
+ return NULL;
+ }
+ return ((_RepoObject *)o)->repo;
+}
+
+PyObject *repoToPyObject(HyRepo repo)
+{
+ _RepoObject *self = (_RepoObject *)repo_Type.tp_alloc(&repo_Type, 0);
+ if (self)
+ self->repo = repo;
+ return (PyObject *)self;
+}
+
+/* functions on the type */
+
+static PyObject *
+repo_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _RepoObject *self = (_RepoObject *)type->tp_alloc(type, 0);
+ if (self) {
+ self->repo = hy_repo_create("(default)");
+ if (self->repo == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ }
+ return (PyObject *) self;
+} CATCH_TO_PYTHON
+
+static int
+repo_init(_RepoObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *name;
+ if (!PyArg_ParseTuple(args, "s", &name))
+ return -1;
+ hy_repo_set_string(self->repo, HY_REPO_NAME, name);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static void
+repo_dealloc(_RepoObject *self)
+{
+ hy_repo_free(self->repo);
+ Py_TYPE(self)->tp_free(self);
+}
+
+/* getsetters */
+
+static PyObject *
+get_int(_RepoObject *self, void *closure) try
+{
+ IntGetSetter *functions = (IntGetSetter*)closure;
+ return PyLong_FromLong(functions->getter(self->repo));
+} CATCH_TO_PYTHON
+
+static int
+set_int(_RepoObject *self, PyObject *value, void *closure) try
+{
+ IntGetSetter *functions = (IntGetSetter*)closure;
+ long num = PyLong_AsLong(value);
+ if (PyErr_Occurred())
+ return -1;
+ if (num > INT_MAX || num < INT_MIN) {
+ PyErr_SetString(PyExc_ValueError, "Value in the integer range expected.");
+ return -1;
+ }
+ functions->setter(self->repo, num);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+get_str(_RepoObject *self, void *closure) try
+{
+ int str_key = (intptr_t)closure;
+ const char *str;
+ PyObject *ret;
+
+ str = hy_repo_get_string(self->repo, str_key);
+ if (str == NULL) {
+ ret = PyString_FromString("");
+ } else {
+ ret = PyString_FromString(str);
+ }
+ return ret; // NULL if PyString_FromString failed
+} CATCH_TO_PYTHON
+
+static int
+set_str(_RepoObject *self, PyObject *value, void *closure) try
+{
+ intptr_t str_key = (intptr_t)closure;
+ PycompString str_value(value);
+ if (!str_value.getCString())
+ return -1;
+ hy_repo_set_string(self->repo, str_key, str_value.getCString());
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static IntGetSetter hy_repo_cost{hy_repo_get_cost, hy_repo_set_cost};
+
+static IntGetSetter hy_repo_priority{hy_repo_get_priority, hy_repo_set_priority};
+
+static PyGetSetDef repo_getsetters[] = {
+ {(char*)"cost", (getter)get_int, (setter)set_int, (char*)"repository cost",
+ (void *)&hy_repo_cost},
+ {(char*)"name", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_NAME},
+ {(char*)"priority", (getter)get_int, (setter)set_int, (char*)"repository priority",
+ (void *)&hy_repo_priority},
+ {(char*)"repomd_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_MD_FN},
+ {(char*)"primary_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_PRIMARY_FN},
+ {(char*)"filelists_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_FILELISTS_FN},
+ {(char*)"modules_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)MODULES_FN},
+ {(char*)"presto_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_PRESTO_FN},
+ {(char*)"updateinfo_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_UPDATEINFO_FN},
+ {(char*)"other_fn", (getter)get_str, (setter)set_str, NULL,
+ (void *)HY_REPO_OTHER_FN},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject repo_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Repo", /*tp_name*/
+ sizeof(_RepoObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) repo_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Repo object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ repo_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)repo_init, /* tp_init */
+ 0, /* tp_alloc */
+ repo_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REPO_PY_H
+#define REPO_PY_H
+
+#include "hy-types.h"
+
+extern PyTypeObject repo_Type;
+
+HyRepo repoFromPyObject(PyObject *o);
+PyObject *repoToPyObject(HyRepo repo);
+
+#endif // REPO_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2019 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Python.h"
+
+
+// hawkey
+#include "libdnf/repo/Repo.hpp"
+#include "dnf-types.h"
+#include "hy-packageset.h"
+#include "hy-repo.h"
+#include "hy-util.h"
+#include "dnf-version.h"
+#include "dnf-sack-private.hpp"
+#include "libdnf/module/ModulePackageContainer.hpp"
+
+// pyhawkey
+#include "exception-py.hpp"
+#include "hawkey-pysys.hpp"
+#include "iutil-py.hpp"
+#include "package-py.hpp"
+#include "repo-py.hpp"
+#include "sack-py.hpp"
+
+#include "pycomp.hpp"
+#include "sack/packageset.hpp"
+
+#include <algorithm>
+#include <functional>
+
+typedef struct {
+ PyObject_HEAD
+ DnfSack *sack;
+ PyObject *custom_package_class;
+ PyObject *custom_package_val;
+ PyObject * ModulePackageContainerPy;
+
+ // g_log handler IDs
+ // Multiple sacks can be created during a run of an application and each
+ // sack opens a log file and registers two g_log handlers. To avoid dangling
+ // handlers with invalid FILE pointers (we close them when destroying the
+ // sack), we need to keep track of the handlers so that we can also remove
+ // them.
+ //
+ // g_log is clever about adding log handlers. It does store all handlers
+ // registered for a given domain, but only the one that was registered last
+ // is used. If you remove the last registered one, the next in line will be
+ // used. That means stacking sacks is ok, the handler from the last
+ // undeleted sack will be the one that is used.
+ guint default_log_handler_id;
+ guint libdnf_log_handler_id;
+
+ FILE *log_out;
+} _SackObject;
+
+typedef struct {
+ PyObject_HEAD
+ libdnf::ModulePackageContainer * ptr;
+ void * ty;
+ int own;
+ PyObject * next;
+} ModulePackageContainerPyObject;
+
+PyObject *
+new_package(PyObject *sack, Id id)
+{
+ _SackObject *self;
+
+ if (!sackObject_Check(sack)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a _hawkey.Sack object.");
+ return NULL;
+ }
+ self = (_SackObject*)sack;
+ UniquePtrPyObject arglist;
+ if (self->custom_package_class || self->custom_package_val) {
+ arglist.reset(Py_BuildValue("(Oi)O", sack, id, self->custom_package_val));
+ } else {
+ arglist.reset(Py_BuildValue("((Oi))", sack, id));
+ }
+ if (!arglist)
+ return NULL;
+ if (self->custom_package_class)
+ return PyObject_CallObject(self->custom_package_class, arglist.get());
+ return PyObject_CallObject((PyObject*)&package_Type, arglist.get());
+}
+
+DnfSack *
+sackFromPyObject(PyObject *o)
+{
+ if (!sackObject_Check(o)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a _hawkey.Sack object.");
+ return NULL;
+ }
+ return ((_SackObject *)o)->sack;
+}
+
+int
+sack_converter(PyObject *o, DnfSack **sack_ptr)
+{
+ DnfSack *sack = sackFromPyObject(o);
+ if (sack == NULL)
+ return 0;
+ *sack_ptr = sack;
+ return 1;
+}
+
+/* helpers */
+static PyObject *
+repo_enabled(_SackObject *self, PyObject *reponame, int enabled)
+{
+ PycompString cname(reponame);
+ if (!cname.getCString())
+ return NULL;
+ dnf_sack_repo_enabled(self->sack, cname.getCString(), enabled);
+ Py_RETURN_NONE;
+}
+
+/* functions on the type */
+
+static void
+sack_dealloc(_SackObject *o)
+{
+ Py_XDECREF(o->custom_package_class);
+ Py_XDECREF(o->custom_package_val);
+ if (o->sack) {
+ if (auto moduleContainer = o->ModulePackageContainerPy) {
+ dnf_sack_set_module_container(o->sack, NULL);
+ Py_DECREF(moduleContainer);
+ }
+ g_object_unref(o->sack);
+ }
+
+ if (o->log_out) {
+ g_log_remove_handler(nullptr, o->default_log_handler_id);
+ g_log_remove_handler("libdnf", o->libdnf_log_handler_id);
+ fclose(o->log_out);
+ }
+
+ Py_TYPE(o)->tp_free(o);
+}
+
+static PyObject *
+sack_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _SackObject *self = (_SackObject *)type->tp_alloc(type, 0);
+
+ if (self) {
+ self->sack = NULL;
+ self->custom_package_class = NULL;
+ self->custom_package_val = NULL;
+ self->ModulePackageContainerPy = NULL;
+ }
+ return (PyObject *)self;
+} CATCH_TO_PYTHON
+
+const char *
+log_level_name(int level)
+{
+ switch (level) {
+ case G_LOG_FLAG_FATAL:
+ return "FATAL";
+ case G_LOG_LEVEL_ERROR:
+ return "ERROR";
+ case G_LOG_LEVEL_CRITICAL:
+ return "CRITICAL";
+ case G_LOG_LEVEL_WARNING:
+ return "WARN";
+ case G_LOG_LEVEL_DEBUG:
+ return "DEBUG";
+ case G_LOG_LEVEL_INFO:
+ return "INFO";
+ default:
+ return "(level?)";
+ }
+}
+
+static void
+log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
+{
+ time_t t = time(NULL);
+ struct tm tm;
+ char timestr[32];
+
+ FILE *log_out = (FILE*) user_data;
+ localtime_r(&t, &tm);
+ strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S%z ", &tm);
+ gchar *msg = g_strjoin("", timestr, log_level_name(log_level), " ", message, "\n", NULL);
+ fwrite(msg, strlen(msg), 1, log_out);
+ fflush(log_out);
+ g_free(msg);
+}
+
+static void
+log_handler_noop(const gchar *, GLogLevelFlags, const gchar *, gpointer)
+{
+}
+
+static gboolean
+sack_set_logfile(_SackObject *self, const gchar *path, bool debug)
+{
+ self->log_out = fopen(path, "a");
+
+ if (!self->log_out)
+ return FALSE;
+
+ // The default log handler prints messages that weren't handled by any
+ // other logger to stderr/stdout, we do not want that
+ g_log_set_default_handler(log_handler_noop, nullptr);
+
+ GLogLevelFlags log_mask = debug ? G_LOG_LEVEL_MASK : static_cast<GLogLevelFlags>(
+ G_LOG_LEVEL_INFO |
+ G_LOG_LEVEL_MESSAGE |
+ G_LOG_LEVEL_WARNING |
+ G_LOG_LEVEL_CRITICAL |
+ G_LOG_LEVEL_ERROR);
+
+ // set the handler for the default domain as well as "libdnf"
+ self->default_log_handler_id = g_log_set_handler(nullptr, log_mask, log_handler, self->log_out);
+ self->libdnf_log_handler_id = g_log_set_handler("libdnf", log_mask, log_handler, self->log_out);
+
+ g_info("=== Started libdnf-%d.%d.%d ===", LIBDNF_MAJOR_VERSION,
+ LIBDNF_MINOR_VERSION, LIBDNF_MICRO_VERSION);
+ return TRUE;
+}
+
+static int
+sack_init(_SackObject *self, PyObject *args, PyObject *kwds) try
+{
+ g_autoptr(GError) error = NULL;
+ PyObject *custom_class = NULL;
+ PyObject *custom_val = NULL;
+ PycompString cachedir;
+ const char *arch = NULL;
+ const char *rootdir = NULL;
+ PyObject *cachedir_py = NULL;
+ PyObject *logfile_py = NULL;
+ self->log_out = NULL;
+ int make_cache_dir = 0;
+ PyObject *debug_object = nullptr;
+ gboolean all_arch = FALSE;
+ const char *kwlist[] = {"cachedir", "arch", "rootdir", "pkgcls",
+ "pkginitval", "make_cache_dir", "logfile", "logdebug",
+ "all_arch", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OssOOiOO!i", (char**) kwlist,
+ &cachedir_py, &arch, &rootdir,
+ &custom_class, &custom_val,
+ &make_cache_dir, &logfile_py,
+ &PyBool_Type, &debug_object,
+ &all_arch))
+ return -1;
+
+ bool debug = debug_object != nullptr && PyObject_IsTrue(debug_object);
+
+ if (cachedir_py != NULL) {
+ cachedir = PycompString(cachedir_py);
+ if (!cachedir.getCString())
+ return -1;
+ }
+ int flags = 0;
+ if (make_cache_dir)
+ flags |= DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR;
+ self->sack = dnf_sack_new();
+ if (all_arch) {
+ dnf_sack_set_all_arch(self->sack, all_arch);
+ } else {
+ if (!dnf_sack_set_arch(self->sack, arch, &error)) {
+ PyErr_SetString(HyExc_Arch, "Unrecognized arch for the sack.");
+ return -1;
+ }
+ }
+ dnf_sack_set_rootdir(self->sack, rootdir);
+ dnf_sack_set_cachedir(self->sack, cachedir.getCString());
+ if (logfile_py != NULL) {
+ PycompString logfile(logfile_py);
+ if (!logfile.getCString())
+ return -1;
+ if (!sack_set_logfile(self, logfile.getCString(), debug)) {
+ PyErr_Format(PyExc_IOError, "Failed to open log file: %s", logfile.getCString());
+ return -1;
+ }
+ }
+ if (!dnf_sack_setup(self->sack, flags, &error)) {
+ switch (error->code) {
+ case DNF_ERROR_FILE_INVALID:
+ PyErr_SetString(PyExc_IOError,
+ "Failed creating working files for the Sack.");
+ break;
+ case DNF_ERROR_INVALID_ARCHITECTURE:
+ PyErr_SetString(HyExc_Arch, "Unrecognized arch for the sack.");
+ break;
+ default:
+ assert(0);
+ }
+ return -1;
+ }
+
+ if (custom_class && custom_class != Py_None) {
+ if (!PyType_Check(custom_class)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a class object.");
+ return -1;
+ }
+ Py_INCREF(custom_class);
+ self->custom_package_class = custom_class;
+ }
+ if (custom_val && custom_val != Py_None) {
+ Py_INCREF(custom_val);
+ self->custom_package_val = custom_val;
+
+ }
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+/* getsetters */
+
+static PyObject *
+get_cache_dir(_SackObject *self, void *unused) try
+{
+ const char *cstr = dnf_sack_get_cache_dir(self->sack);
+ if (cstr == NULL)
+ Py_RETURN_NONE;
+ return PyString_FromString(cstr);
+} CATCH_TO_PYTHON
+
+static int
+set_installonly(_SackObject *self, PyObject *obj, void *unused) try
+{
+ if (!PySequence_Check(obj)) {
+ PyErr_SetString(PyExc_AttributeError, "Expected a sequence.");
+ return -1;
+ }
+
+ const int len = PySequence_Length(obj);
+ PycompString pStrings[len];
+ const char *strings[len + 1];
+
+ for (int i = 0; i < len; ++i) {
+ UniquePtrPyObject item(PySequence_GetItem(obj, i));
+ if (PyUnicode_Check(item.get()) || PyString_Check(item.get())) {
+ pStrings[i] = PycompString(item.get());
+ strings[i] = pStrings[i].getCString();
+ } else
+ strings[i] = NULL;
+ if (strings[i] == NULL)
+ return -1;
+ }
+ strings[len] = NULL;
+
+ DnfSack *sack = self->sack;
+ dnf_sack_set_installonly(sack, strings);
+
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static int
+set_installonly_limit(_SackObject *self, PyObject *obj, void *unused) try
+{
+ int limit = (int)PyLong_AsLong(obj);
+ if (PyErr_Occurred())
+ return -1;
+ dnf_sack_set_installonly_limit(self->sack, limit);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static int
+set_module_container(_SackObject *self, PyObject *obj, void *unused) try
+{
+ UniquePtrPyObject thisPyContainer(PyObject_GetAttrString(obj, "this"));
+ auto swigContainer = reinterpret_cast< ModulePackageContainerPyObject * >(thisPyContainer.get());
+ if (swigContainer == nullptr) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse ModuleContainer object");
+ return -1;
+ }
+ auto moduleContainer = swigContainer->ptr;
+ auto sack = self->sack;
+ if (auto oldConteynerPy = self->ModulePackageContainerPy) {
+ Py_XDECREF(oldConteynerPy);
+ dnf_sack_set_module_container(sack, moduleContainer);
+ } else {
+ auto oldContainer = dnf_sack_set_module_container(sack, moduleContainer);
+ if (oldContainer) {
+ delete oldContainer;
+ }
+ }
+ self->ModulePackageContainerPy = obj;
+ Py_INCREF(obj);
+
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+get_module_container(_SackObject *self, void *unused) try
+{
+ if (auto moduleConteinerPy = self->ModulePackageContainerPy) {
+ Py_INCREF(moduleConteinerPy);
+ return moduleConteinerPy;
+ }
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static int
+set_allow_vendor_change(_SackObject *self, PyObject *obj, void *unused) try
+{
+ gboolean vendor = PyObject_IsTrue(obj);
+ if (PyErr_Occurred())
+ return -1;
+ dnf_sack_set_allow_vendor_change(self->sack, vendor);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static PyGetSetDef sack_getsetters[] = {
+ {(char*)"cache_dir", (getter)get_cache_dir, NULL, NULL, NULL},
+ {(char*)"installonly", NULL, (setter)set_installonly, NULL, NULL},
+ {(char*)"installonly_limit", NULL, (setter)set_installonly_limit, NULL, NULL},
+ {(char*)"allow_vendor_change", NULL,
+ (setter)set_allow_vendor_change, NULL, NULL},
+ {(char*)"_moduleContainer", (getter)get_module_container, (setter)set_module_container,
+ NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+/* object methods */
+
+static PyObject *
+evr_cmp(_SackObject *self, PyObject *args) try
+{
+ const char *evr1 = NULL, *evr2 = NULL;
+
+ if (!PyArg_ParseTuple(args, "ss", &evr1, &evr2))
+ return NULL;
+ int cmp = dnf_sack_evr_cmp(self->sack, evr1, evr2);
+ return PyLong_FromLong(cmp);
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_running_kernel(_SackObject *self, PyObject *unused) try
+{
+ DnfSack *sack = self->sack;
+ DnfPackage *cpkg = dnf_sack_get_running_kernel(sack);
+
+ if (cpkg == NULL)
+ Py_RETURN_NONE;
+ PyObject *pkg = new_package((PyObject*)self, dnf_package_get_id(cpkg));
+ g_object_unref(cpkg);
+ return pkg;
+} CATCH_TO_PYTHON
+
+static PyObject *
+create_cmdline_repo(_SackObject *self, PyObject *unused) try
+{
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+create_package(_SackObject *self, PyObject *solvable_id) try
+{
+ Id id = PyLong_AsLong(solvable_id);
+ if (id <= 0) {
+ PyErr_SetString(PyExc_TypeError, "Expected a positive integer.");
+ return NULL;
+ }
+ return new_package((PyObject*)self, id);
+} CATCH_TO_PYTHON
+
+static PyObject *
+add_cmdline_package(_SackObject *self, PyObject *fn_obj) try
+{
+ DnfPackage *cpkg;
+ PyObject *pkg;
+ PycompString fn(fn_obj);
+
+ if (!fn.getCString())
+ return NULL;
+ cpkg = dnf_sack_add_cmdline_package_nochecksum(self->sack, fn.getCString());
+ if (cpkg == NULL) {
+ PyErr_Format(PyExc_IOError, "Can not load RPM file: %s.", fn.getCString());
+ return NULL;
+ }
+ pkg = new_package((PyObject*)self, dnf_package_get_id(cpkg));
+ g_object_unref(cpkg);
+ return pkg;
+} CATCH_TO_PYTHON
+
+template<void (*sackExcludeIncludeFunc)(DnfSack *, const DnfPackageSet*)>
+static PyObject *
+modify_excl_incl(_SackObject *self, PyObject *o) try
+{
+ DnfSack *sack = self->sack;
+ auto pset = pyseq_to_packageset(o, sack);
+ if (!pset)
+ return NULL;
+ sackExcludeIncludeFunc(sack, pset.get());
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+template<void (*sackExcludeIncludeFunc)(DnfSack *)>
+static PyObject *
+reset_excl_incl(_SackObject *self) try
+{
+ DnfSack *sack = self->sack;
+ sackExcludeIncludeFunc(sack);
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+template<DnfPackageSet * (*sackExcludeIncludeFunc)(DnfSack *)>
+static PyObject *
+get_excl_incl(_SackObject *self) try
+{
+ DnfSack *sack = self->sack;
+ DnfPackageSet * pset = sackExcludeIncludeFunc(sack);
+ if (!pset)
+ return PyList_New(0);
+ PyObject * pyList = packageset_to_pylist(pset, (PyObject *)self);
+ delete pset;
+ return pyList;
+} CATCH_TO_PYTHON
+
+static PyObject *
+set_use_includes(_SackObject *self, PyObject *args) try
+{
+ PyObject *py_enabled;
+ const char *creponame = NULL;
+ if (!PyArg_ParseTuple(args, "O!|z", &PyBool_Type, &py_enabled, &creponame))
+ return NULL;
+
+ gboolean enabled = PyObject_IsTrue(py_enabled);
+ if (!dnf_sack_set_use_includes(self->sack, creponame, enabled)) {
+ PyErr_SetString(PyExc_ValueError, "Can't set use_includes for repo with given name.");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+get_use_includes(_SackObject *self, PyObject *reponame) try
+{
+ DnfSack *sack = self->sack;
+
+ PycompString creponame(reponame);
+ if (!creponame.getCString())
+ return NULL;
+
+ gboolean enabled;
+ if (!dnf_sack_get_use_includes(sack, creponame.getCString(), &enabled)) {
+ PyErr_SetString(PyExc_ValueError, "Can't found repo with given name.");
+ return NULL;
+ }
+
+ if (enabled)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+} CATCH_TO_PYTHON
+
+static PyObject *
+disable_repo(_SackObject *self, PyObject *reponame) try
+{
+ return repo_enabled(self, reponame, 0);
+} CATCH_TO_PYTHON
+
+static PyObject *
+enable_repo(_SackObject *self, PyObject *reponame) try
+{
+ return repo_enabled(self, reponame, 1);
+} CATCH_TO_PYTHON
+
+static PyObject *
+list_arches(_SackObject *self, PyObject *unused) try
+{
+ const char **arches = dnf_sack_list_arches(self->sack);
+ PyObject *list;
+ if (!arches && !dnf_sack_get_all_arch(self->sack)) {
+ PyErr_SetString(HyExc_Runtime, "Arches not initialized");
+ return NULL;
+ }
+
+ if (arches) {
+ list = strlist_to_pylist(arches);
+ g_free(arches);
+ return list;
+ } else {
+ return PyList_New(0);
+ }
+} CATCH_TO_PYTHON
+
+static PyObject *
+filter_modules(_SackObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"module_container", "hotfix_repos", "install_root", "platform_module",
+ "update_only", "debugsolver", "module_obsoletes", NULL};
+ PyObject * pyModuleContainer;
+ PyObject * pyHotfixRepos;
+ char * installRoot = nullptr;
+ char * platformModule = nullptr;
+ PyObject * pyUpdateOnly = nullptr;
+ PyObject * pyDebugSolver = nullptr;
+ PyObject * pyModuleObsoletes = nullptr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOzz|O!O!O!", (char**) kwlist, &pyModuleContainer,
+ &pyHotfixRepos, &installRoot, &platformModule, &PyBool_Type, &pyUpdateOnly,
+ &PyBool_Type, &pyDebugSolver, &PyBool_Type, &pyModuleObsoletes))
+ return 0;
+ bool updateOnly = pyUpdateOnly == NULL || PyObject_IsTrue(pyUpdateOnly);
+ bool debugSolver = pyDebugSolver != NULL && PyObject_IsTrue(pyDebugSolver);
+ bool moduleObsoletes = pyModuleObsoletes != NULL && PyObject_IsTrue(pyModuleObsoletes);
+ UniquePtrPyObject thisPyModuleContainer(PyObject_GetAttrString(pyModuleContainer, "this"));
+ auto swigContainer = reinterpret_cast< ModulePackageContainerPyObject * >(thisPyModuleContainer.get());
+ auto moduleContainer = swigContainer->ptr;
+ std::vector<std::string> hotfixRepos;
+ try {
+ hotfixRepos = pySequenceConverter(pyHotfixRepos);
+ } catch (std::runtime_error &) {
+ return NULL;
+ }
+ std::vector<const char *> hotfixReposCString(hotfixRepos.size() + 1);
+ std::transform(hotfixRepos.begin(), hotfixRepos.end(), hotfixReposCString.begin(),
+ std::mem_fn(&std::string::c_str));
+ try {
+ auto problems = dnf_sack_filter_modules_v2(self->sack, moduleContainer, hotfixReposCString.data(),
+ installRoot, platformModule, updateOnly, debugSolver, moduleObsoletes);
+ if (problems.second == libdnf::ModulePackageContainer::ModuleErrorType::NO_ERROR) {
+ PyObject * returnTuple = PyTuple_New(0);
+ return returnTuple;
+ }
+ PyObject * returnTuple = PyTuple_New(2);
+ PyTuple_SetItem(returnTuple, 0, problemRulesPyConverter(problems.first));
+ PyTuple_SetItem(returnTuple, 1, PyLong_FromLong(int(problems.second)));
+ return returnTuple;
+ } catch (libdnf::ModulePackageContainer::ConflictException & exception) {
+ PyErr_SetString(HyExc_Runtime, exception.what());
+ return NULL;
+ }
+} CATCH_TO_PYTHON
+
+
+static PyObject *
+set_modules_enabled_by_pkgset(_SackObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"module_container", "pkgs", NULL};
+ PyObject * pyModuleContainer;
+ PyObject * pyPkgSet;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", (char**) kwlist, &pyModuleContainer,
+ &pyPkgSet))
+ return NULL;
+ auto pset = pyseq_to_packageset(pyPkgSet, self->sack);
+ if (!pset) {
+ return NULL;
+ }
+
+ UniquePtrPyObject thisPyModuleContainer(PyObject_GetAttrString(pyModuleContainer, "this"));
+ auto swigContainer = reinterpret_cast< ModulePackageContainerPyObject * >(thisPyModuleContainer.get());
+ auto moduleContainer = swigContainer->ptr;
+ auto modules = moduleContainer->requiresModuleEnablement(*pset.get());
+ moduleContainer->enableDependencyTree(modules);
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+typedef struct {
+ PyObject_HEAD
+ libdnf::Repo *ptr;
+ void *ty;
+ int own;
+ PyObject *next;
+} RepoSwigPyObject;
+
+static PyObject *
+load_system_repo(_SackObject *self, PyObject *args, PyObject *kwds)
+{
+ g_autoptr(GError) error = NULL;
+ const char *kwlist[] = {"repo", "build_cache", "load_filelists", "load_presto",
+ NULL};
+
+ PyObject * repoPyObj = NULL;
+ libdnf::Repo * crepo = NULL;
+ int build_cache = 0, unused_1 = 0, unused_2 = 0;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oiii", (char**) kwlist,
+ &repoPyObj,
+ &build_cache, &unused_1, &unused_2))
+ return 0;
+
+ if (repoPyObj) {
+
+ // Is it old deprecated _hawkey.Repo object?
+ crepo = repoFromPyObject(repoPyObj);
+
+ // Or is it swig object?
+ if (!crepo) {
+ UniquePtrPyObject thisRepoPyObj(PyObject_GetAttrString(repoPyObj, "this"));
+ auto repoSwigPyObj = reinterpret_cast<RepoSwigPyObject *>(thisRepoPyObj.get());
+ if (!repoSwigPyObj) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse repoSwigPyObject");
+ return NULL;
+ }
+
+ crepo = repoSwigPyObj->ptr;
+ if (!crepo) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse repo swig object");
+ return NULL;
+ }
+ }
+ }
+
+ int flags = 0;
+ if (build_cache)
+ flags |= DNF_SACK_LOAD_FLAG_BUILD_CACHE;
+
+ gboolean ret = dnf_sack_load_system_repo(self->sack, crepo, flags, &error);
+ if (!ret)
+ return op_error2exc(error);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+load_repo(_SackObject *self, PyObject *args, PyObject *kwds) try
+{
+ const char *kwlist[] = {"repo", "build_cache", "load_filelists", "load_presto",
+ "load_updateinfo", "load_other", NULL};
+
+ PyObject * repoPyObj = NULL;
+ int build_cache = 0, load_filelists = 0, load_presto = 0, load_updateinfo = 0, load_other = 0;
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiiii", (char**) kwlist,
+ &repoPyObj,
+ &build_cache, &load_filelists,
+ &load_presto, &load_updateinfo, &load_other))
+ return 0;
+
+ // Is it old deprecated _hawkey.Repo object?
+ libdnf::Repo * crepo = repoFromPyObject(repoPyObj);
+
+ // Or is it swig object?
+ if (!crepo) {
+ UniquePtrPyObject thisRepoPyObj(PyObject_GetAttrString(repoPyObj, "this"));
+ auto repoSwigPyObj = reinterpret_cast<RepoSwigPyObject *>(thisRepoPyObj.get());
+ if (!repoSwigPyObj) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse repoSwigPyObject");
+ return NULL;
+ }
+
+ crepo = repoSwigPyObj->ptr;
+ if (!crepo) {
+ PyErr_SetString(PyExc_SystemError, "Unable to parse repo swig object");
+ return NULL;
+ }
+ }
+
+ int flags = 0;
+ gboolean ret = 0;
+ g_autoptr(GError) error = NULL;
+ if (build_cache)
+ flags |= DNF_SACK_LOAD_FLAG_BUILD_CACHE;
+ if (load_filelists)
+ flags |= DNF_SACK_LOAD_FLAG_USE_FILELISTS;
+ if (load_presto)
+ flags |= DNF_SACK_LOAD_FLAG_USE_PRESTO;
+ if (load_updateinfo)
+ flags |= DNF_SACK_LOAD_FLAG_USE_UPDATEINFO;
+ if (load_other)
+ flags |= DNF_SACK_LOAD_FLAG_USE_OTHER;
+ Py_BEGIN_ALLOW_THREADS;
+ ret = dnf_sack_load_repo(self->sack, crepo, flags, &error);
+ Py_END_ALLOW_THREADS;
+ if (!ret)
+ return op_error2exc(error);
+ Py_RETURN_NONE;
+} CATCH_TO_PYTHON
+
+static Py_ssize_t
+len(_SackObject *self) try
+{
+ return dnf_sack_count(self->sack);
+} CATCH_TO_PYTHON_INT
+
+static PyObject *
+deepcopy(_SackObject *self, PyObject *args, PyObject *kwds) try
+{
+ PyErr_SetString(PyExc_NotImplementedError, "sack can't be deepcopied");
+ return NULL;
+} CATCH_TO_PYTHON
+
+static struct
+PyMethodDef sack_methods[] = {
+ {"__deepcopy__", (PyCFunction)deepcopy, METH_KEYWORDS|METH_VARARGS,
+ NULL},
+ {"evr_cmp", (PyCFunction)evr_cmp, METH_VARARGS,
+ NULL},
+ {"get_running_kernel", (PyCFunction)get_running_kernel, METH_NOARGS,
+ NULL},
+ {"create_cmdline_repo", (PyCFunction)create_cmdline_repo, METH_NOARGS,
+ NULL},
+ {"create_package", (PyCFunction)create_package, METH_O,
+ NULL},
+ {"add_cmdline_package", (PyCFunction)add_cmdline_package, METH_O,
+ NULL},
+ {"add_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_add_excludes>, METH_O, NULL},
+ {"add_module_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_add_module_excludes>, METH_O,
+ NULL},
+ {"add_includes", (PyCFunction)modify_excl_incl<&dnf_sack_add_includes>, METH_O, NULL},
+ {"remove_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_remove_excludes>, METH_O, NULL},
+ {"remove_module_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_remove_module_excludes>,
+ METH_O, NULL},
+ {"remove_includes", (PyCFunction)modify_excl_incl<&dnf_sack_remove_includes>, METH_O, NULL},
+ {"set_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_set_excludes>, METH_O, NULL},
+ {"set_module_excludes", (PyCFunction)modify_excl_incl<&dnf_sack_set_module_excludes>, METH_O,
+ NULL},
+ {"set_includes", (PyCFunction)modify_excl_incl<&dnf_sack_set_includes>, METH_O, NULL},
+ {"reset_excludes", (PyCFunction)reset_excl_incl<&dnf_sack_reset_excludes>, METH_NOARGS,
+ NULL},
+ {"reset_module_excludes", (PyCFunction)reset_excl_incl<&dnf_sack_reset_module_excludes>,
+ METH_NOARGS, NULL},
+ {"reset_includes", (PyCFunction)reset_excl_incl<&dnf_sack_reset_includes>, METH_NOARGS,
+ NULL},
+ {"get_excludes", (PyCFunction)get_excl_incl<&dnf_sack_get_excludes>, METH_NOARGS,
+ NULL},
+ {"get_module_excludes", (PyCFunction)get_excl_incl<&dnf_sack_get_module_excludes>, METH_NOARGS,
+ NULL},
+ {"get_includes", (PyCFunction)get_excl_incl<&dnf_sack_get_includes>, METH_NOARGS,
+ NULL},
+ {"set_use_includes", (PyCFunction)set_use_includes, METH_VARARGS,
+ NULL},
+ {"get_use_includes", (PyCFunction)get_use_includes, METH_O,
+ NULL},
+ {"disable_repo", (PyCFunction)disable_repo, METH_O,
+ NULL},
+ {"enable_repo", (PyCFunction)enable_repo, METH_O,
+ NULL},
+ {"list_arches", (PyCFunction)list_arches, METH_NOARGS,
+ NULL},
+ {"filter_modules", (PyCFunction)filter_modules, METH_VARARGS | METH_KEYWORDS, NULL},
+ {"set_modules_enabled_by_pkgset", (PyCFunction)set_modules_enabled_by_pkgset,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"load_system_repo", (PyCFunction)load_system_repo,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"load_repo", (PyCFunction)load_repo, METH_VARARGS | METH_KEYWORDS,
+ NULL},
+ {NULL} /* sentinel */
+};
+
+PySequenceMethods sack_sequence = {
+ (lenfunc)len, /* sq_length */
+};
+
+PyTypeObject sack_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Sack", /*tp_name*/
+ sizeof(_SackObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) sack_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ &sack_sequence, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Sack object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ 0, /* tp_iternext */
+ sack_methods, /* tp_methods */
+ 0, /* tp_members */
+ sack_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)sack_init, /* tp_init */
+ 0, /* tp_alloc */
+ sack_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SACK_PY_H
+#define SACK_PY_H
+
+// libsolv
+#include <solv/pooltypes.h>
+
+// hawkey
+#include "hy-types.h"
+
+extern PyTypeObject sack_Type;
+
+#define sackObject_Check(o) PyObject_TypeCheck(o, &sack_Type)
+
+DnfSack *sackFromPyObject(PyObject *o);
+int sack_converter(PyObject *o, DnfSack **sack_ptr);
+
+PyObject *new_package(PyObject *sack, Id id);
+const char *log_level_name(int level);
+
+#endif // SACK_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+#include "hy-selector.h"
+
+#include "exception-py.hpp"
+#include "hy-query.h"
+#include "iutil-py.hpp"
+#include "query-py.hpp"
+#include "sack-py.hpp"
+#include "selector-py.hpp"
+
+#include "pycomp.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ HySelector sltr;
+ PyObject *sack;
+} _SelectorObject;
+
+PyObject *
+SelectorToPyObject(HySelector selector, PyObject *sack)
+{
+ _SelectorObject *self = (_SelectorObject *)selector_Type.tp_alloc(&selector_Type, 0);
+ if (self) {
+ self->sltr = selector;
+ self->sack = sack;
+ Py_INCREF(sack);
+ }
+ return (PyObject *) self;
+}
+
+int
+selector_converter(PyObject *o, HySelector *sltr_ptr)
+{
+ if (!PyType_IsSubtype(o->ob_type, &selector_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected a Selector object.");
+ return 0;
+ }
+ *sltr_ptr = ((_SelectorObject *)o)->sltr;
+
+ return 1;
+}
+
+static PyObject *
+selector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) try
+{
+ _SelectorObject *self = (_SelectorObject*)type->tp_alloc(type, 0);
+ if (self) {
+ self->sltr = NULL;
+ self->sack = NULL;
+ }
+ return (PyObject*)self;
+} CATCH_TO_PYTHON
+
+static int
+selector_init(_SelectorObject *self, PyObject *args, PyObject *kwds) try
+{
+ PyObject *sack;
+ DnfSack *csack;
+
+ if (!PyArg_ParseTuple(args, "O!", &sack_Type, &sack))
+ return -1;
+ csack = sackFromPyObject(sack);
+ if (csack == NULL)
+ return -1;
+ self->sack = sack;
+ Py_INCREF(self->sack); // sack has to kept around until we are
+ self->sltr = hy_selector_create(csack);
+ return 0;
+} CATCH_TO_PYTHON_INT
+
+static void
+selector_dealloc(_SelectorObject *self)
+{
+ if (self->sltr)
+ hy_selector_free(self->sltr);
+
+ Py_XDECREF(self->sack);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+matches(_SelectorObject *self, PyObject *args) try
+{
+ GPtrArray *plist = hy_selector_matches(self->sltr);
+ PyObject *list = packagelist_to_pylist(plist, self->sack);
+ g_ptr_array_unref(plist);
+ return list;
+} CATCH_TO_PYTHON
+
+static _SelectorObject *
+set(_SelectorObject *self, PyObject *args, PyObject *kwds) try
+{
+ gboolean ret = filter_internal(NULL, self->sltr, self->sack, args, kwds);
+ if (!ret) {
+ return NULL;
+ }
+ Py_INCREF(self);
+ return self;
+} CATCH_TO_PYTHON
+
+static struct PyMethodDef selector_methods[] = {
+ {"matches", (PyCFunction)matches, METH_NOARGS,
+ NULL},
+ {"set", (PyCFunction)set, METH_KEYWORDS|METH_VARARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject selector_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Selector", /*tp_name*/
+ sizeof(_SelectorObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) selector_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Selector object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ 0, /* tp_iternext */
+ selector_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)selector_init, /* tp_init */
+ 0, /* tp_alloc */
+ selector_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SELECTOR_PY_H
+#define SELECTOR_PY_H
+
+#include "hy-types.h"
+PyObject *SelectorToPyObject(HySelector selector, PyObject *sack);
+extern PyTypeObject selector_Type;
+
+int selector_converter(PyObject *o, HySelector *sltr_ptr);
+
+#endif // SELECTOR_PY_H
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+#include <vector>
+
+#include "sack/query.hpp"
+
+// hawkey
+#include "hy-iutil.h"
+#include "nevra.hpp"
+#include "nsvcap.hpp"
+#include "dnf-sack.h"
+#include "hy-subject.h"
+#include "hy-types.h"
+
+// pyhawkey
+#include "iutil-py.hpp"
+#include "nevra-py.hpp"
+#include "nsvcap-py.hpp"
+#include "pycomp.hpp"
+#include "query-py.hpp"
+#include "reldep-py.hpp"
+#include "sack-py.hpp"
+#include "selector-py.hpp"
+#include "subject-py.hpp"
+
+typedef struct {
+ PyObject_HEAD
+ HySubject pattern;
+ bool icase;
+} _SubjectObject;
+
+static PyObject *
+get_icase(_SubjectObject *self, void *closure)
+{
+ if (self->icase)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
+}
+
+static PyObject *
+get_pattern(_SubjectObject *self, void *closure)
+{
+ if (self->pattern == NULL)
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(self->pattern);
+}
+
+static PyGetSetDef subject_getsetters[] = {
+ {(char*)"icase", (getter)get_icase, NULL, NULL, NULL},
+ {(char*)"pattern", (getter)get_pattern, NULL, NULL, NULL},
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+subject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ _SubjectObject *self = (_SubjectObject*)type->tp_alloc(type, 0);
+ if (self) {
+ self->pattern = NULL;
+ self->icase = FALSE;
+ }
+ return (PyObject*)self;
+}
+
+static void
+subject_dealloc(_SubjectObject *self)
+{
+ hy_subject_free(self->pattern);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static int
+subject_init(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *py_pattern;
+ PyObject *icase = NULL;
+ const char *kwlist[] = { "pattern", "ignore_case", NULL };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O!", (char**) kwlist,
+ &py_pattern, &PyBool_Type, &icase)) {
+ return -1;
+ }
+ self->icase = icase != NULL && PyObject_IsTrue(icase);
+ PycompString pattern(py_pattern);
+ if (!pattern.getCString())
+ return -1;
+ self->pattern = g_strdup(pattern.getCString());
+ return 0;
+}
+
+template<typename T, T last_element>
+static std::vector<T>
+fill_form(PyObject *o)
+{
+ if (PyList_Check(o)) {
+ std::vector<T> cforms;
+ cforms.reserve(PyList_Size(o) + 1);
+ bool error{false};
+ for (Py_ssize_t i = 0; i < PyList_Size(o); ++i) {
+ PyObject *form = PyList_GetItem(o, i);
+ if (!PyInt_Check(form)) {
+ error = true;
+ break;
+ }
+ cforms.push_back(static_cast<T>(PyLong_AsLong(form)));
+ }
+ if (!error) {
+ cforms.push_back(last_element);
+ return cforms;
+ }
+ }
+ else if (PyInt_Check(o))
+ return {static_cast<T>(PyLong_AsLong(o)), last_element};
+
+ PyErr_SetString(PyExc_TypeError, "Malformed subject forms.");
+ return {};
+}
+
+/* object methods */
+
+static bool
+addNevraToPyList(PyObject * pyList, libdnf::Nevra && nevraObj)
+{
+ auto cNevra = new libdnf::Nevra(std::move(nevraObj));
+ UniquePtrPyObject nevra(nevraToPyObject(cNevra));
+ if (!nevra) {
+ delete cNevra;
+ return false;
+ }
+ int rc = PyList_Append(pyList, nevra.get());
+ if (rc == -1)
+ return false;
+ return true;
+}
+
+static PyObject *
+get_nevra_possibilities(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *forms = NULL;
+ const char *kwlist[] = { "forms", NULL };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", (char**) kwlist, &forms)) {
+ return NULL;
+ }
+
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+ libdnf::Nevra nevraObj;
+ if (forms && forms != Py_None) {
+ if (PyInt_Check(forms)) {
+ if (nevraObj.parse(self->pattern, static_cast<HyForm>(PyLong_AsLong(forms)))) {
+ if (!addNevraToPyList(list.get(), std::move(nevraObj)))
+ return NULL;
+ }
+ return list.release();
+ }
+ else if (PyList_Check(forms)) {
+ bool error = false;
+ for (Py_ssize_t i = 0; i < PyList_Size(forms); ++i) {
+ PyObject *form = PyList_GetItem(forms, i);
+ if (!PyInt_Check(form)) {
+ error = true;
+ break;
+ }
+ if (nevraObj.parse(self->pattern, static_cast<HyForm>(PyLong_AsLong(form)))) {
+ if (!addNevraToPyList(list.get(), std::move(nevraObj)))
+ return NULL;
+ }
+ }
+ if (!error)
+ return list.release();
+ }
+ PyErr_SetString(PyExc_TypeError, "Malformed subject forms.");
+ return NULL;
+ } else {
+ for (std::size_t i = 0; HY_FORMS_MOST_SPEC[i] != _HY_FORM_STOP_; ++i) {
+ if (nevraObj.parse(self->pattern, HY_FORMS_MOST_SPEC[i])) {
+ if (!addNevraToPyList(list.get(), std::move(nevraObj)))
+ return NULL;
+ }
+ }
+ }
+ return list.release();
+}
+
+static bool
+addNsvcapToPyList(PyObject * pyList, libdnf::Nsvcap && nevraObj)
+{
+ auto cNsvcap = new libdnf::Nsvcap(std::move(nevraObj));
+ UniquePtrPyObject nsvcap(nsvcapToPyObject(cNsvcap));
+ if (!nsvcap) {
+ delete cNsvcap;
+ return false;
+ }
+ int rc = PyList_Append(pyList, nsvcap.get());
+ if (rc == -1)
+ return false;
+ return true;
+}
+
+static PyObject *
+nsvcap_possibilities(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *forms = NULL;
+ const char *kwlist[] = { "form", NULL };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", (char**) kwlist, &forms)) {
+ return NULL;
+ }
+
+ UniquePtrPyObject list(PyList_New(0));
+ if (!list)
+ return NULL;
+ libdnf::Nsvcap nsvcapObj;
+ if (forms && forms != Py_None) {
+ if (PyInt_Check(forms)) {
+ if (nsvcapObj.parse(self->pattern, static_cast<HyModuleForm>(PyLong_AsLong(forms)))) {
+ if (!addNsvcapToPyList(list.get(), std::move(nsvcapObj)))
+ return NULL;
+ }
+ return list.release();
+ }
+ else if (PyList_Check(forms)) {
+ bool error = false;
+ for (Py_ssize_t i = 0; i < PyList_Size(forms); ++i) {
+ PyObject *form = PyList_GetItem(forms, i);
+ if (!PyInt_Check(form)) {
+ error = true;
+ break;
+ }
+ if (nsvcapObj.parse(self->pattern, static_cast<HyModuleForm>(PyLong_AsLong(form)))) {
+ if (!addNsvcapToPyList(list.get(), std::move(nsvcapObj)))
+ return NULL;
+ }
+ }
+ if (!error)
+ return list.release();
+ }
+ PyErr_SetString(PyExc_TypeError, "Malformed subject forms.");
+ return NULL;
+ } else {
+ for (std::size_t i = 0; HY_MODULE_FORMS_MOST_SPEC[i] != _HY_MODULE_FORM_STOP_; ++i) {
+ if (nsvcapObj.parse(self->pattern, HY_MODULE_FORMS_MOST_SPEC[i])) {
+ if (!addNsvcapToPyList(list.get(), std::move(nsvcapObj)))
+ return NULL;
+ }
+ }
+ }
+ return list.release();
+
+}
+
+static PyObject *
+get_solution(_SubjectObject *self, PyObject *args, PyObject *kwds, HyNevra *nevra)
+{
+ PyObject *sack;
+ DnfSack *csack;
+ PyObject *forms = NULL;
+ PyObject *with_nevra = NULL;
+ PyObject *with_provides = NULL;
+ PyObject *with_filenames = NULL;
+ PyObject *with_src = NULL;
+ PyObject *init_query = NULL;
+ const char *kwlist[] = {"sack", "with_nevra", "with_provides", "with_filenames", "forms",
+ "with_src", "query", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!O!O!OO!O!", (char**) kwlist, &sack_Type, &sack,
+ &PyBool_Type, &with_nevra, &PyBool_Type, &with_provides,
+ &PyBool_Type, &with_filenames, &forms, &PyBool_Type, &with_src, &query_Type, &init_query)) {
+ return NULL;
+ }
+ std::vector<HyForm> cforms;
+ if ((forms != NULL) && (forms != Py_None) &&
+ ((!PyList_Check(forms)) || (PyList_Size(forms) > 0))) {
+ cforms = fill_form<HyForm, _HY_FORM_STOP_>(forms);
+ if (cforms.empty())
+ return NULL;
+ }
+ gboolean c_with_nevra = with_nevra == NULL || PyObject_IsTrue(with_nevra);
+ gboolean c_with_provides = with_provides == NULL || PyObject_IsTrue(with_provides);
+ gboolean c_with_filenames = with_filenames == NULL || PyObject_IsTrue(with_filenames);
+ gboolean c_with_src = with_src == NULL || PyObject_IsTrue(with_src);
+ csack = sackFromPyObject(sack);
+ auto c_init_query = init_query ? queryFromPyObject(init_query) : NULL;
+
+ std::unique_ptr<libdnf::Query> query;
+ if (c_init_query)
+ query.reset(new libdnf::Query(*c_init_query));
+ else
+ query.reset(new libdnf::Query(csack));
+ if (!c_with_src)
+ query->addFilter(HY_PKG_ARCH, HY_NEQ, "src");
+
+ auto ret = query->filterSubject(self->pattern, cforms.empty() ? NULL : cforms.data(),
+ self->icase, c_with_nevra, c_with_provides, c_with_filenames);
+
+ *nevra = ret.second.release();
+
+ return queryToPyObject(query.release(), sack, &query_Type);
+}
+
+static PyObject *
+get_best_query(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ HyNevra nevra{nullptr};
+ PyObject *py_query = get_solution(self, args, kwds, &nevra);
+ delete nevra;
+ return py_query;
+}
+
+static PyObject *
+get_best_selector(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *sack;
+ PyObject *forms = NULL;
+ PyObject *obsoletes = NULL;
+ char *reponame = NULL;
+ const char *kwlist[] = {"sack", "forms", "obsoletes", "reponame", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OO!z", (char**) kwlist, &sack_Type, &sack,
+ &forms, &PyBool_Type, &obsoletes, &reponame)) {
+ return NULL;
+ }
+ std::vector<HyForm> cforms;
+ if ((forms != NULL) && (forms != Py_None) &&
+ ((!PyList_Check(forms)) || (PyList_Size(forms) > 0))) {
+ cforms = fill_form<HyForm, _HY_FORM_STOP_>(forms);
+ if (cforms.empty())
+ return NULL;
+ }
+
+ bool c_obsoletes = obsoletes == NULL || PyObject_IsTrue(obsoletes);
+ DnfSack *csack = sackFromPyObject(sack);
+ HySelector c_selector = hy_subject_get_best_selector(self->pattern, csack,
+ cforms.empty() ? NULL : cforms.data(), c_obsoletes, reponame);
+ PyObject *selector = SelectorToPyObject(c_selector, sack);
+ return selector;
+}
+
+static PyObject *
+get_best_solution(_SubjectObject *self, PyObject *args, PyObject *kwds)
+{
+ HyNevra nevra{nullptr};
+
+ UniquePtrPyObject q(get_solution(self, args, kwds, &nevra));
+ if (!q) {
+ delete nevra;
+ return NULL;
+ }
+ PyObject *ret_dict = PyDict_New();
+ PyDict_SetItem(ret_dict, PyString_FromString("query"), q.get());
+ if (nevra) {
+ UniquePtrPyObject n(nevraToPyObject(nevra));
+ PyDict_SetItem(ret_dict, PyString_FromString("nevra"), n.get());
+ }
+ else
+ PyDict_SetItem(ret_dict, PyString_FromString("nevra"), Py_None);
+
+ return ret_dict;
+}
+
+static struct PyMethodDef subject_methods[] = {
+ {"get_nevra_possibilities", (PyCFunction) get_nevra_possibilities,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_nevra_possibilities(self, forms=None)\n"
+ "# :api\n"
+ "forms: list of hawkey NEVRA forms like [hawkey.FORM_NEVRA, hawkey.FORM_NEVR]\n"
+ "return: object with every possible nevra. Each possible nevra is represented by Class "
+ "NEVRA object (libdnf) that have attributes name, epoch, version, release, arch"},
+ {"nsvcap_possibilities", (PyCFunction) nsvcap_possibilities,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"get_best_query", (PyCFunction) get_best_query,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_best_query(self, sack, with_nevra=True, with_provides=True, with_filenames=True,\n"
+ " forms=None, with_src=True, query=None)\n"
+ "# :api\n"
+ "Try to find first real solution for subject if it is NEVRA, provide or file name\n"
+ "return: query"},
+ {"get_best_selector", (PyCFunction) get_best_selector, METH_VARARGS | METH_KEYWORDS,
+ "get_best_selector(self, sack, forms=None, obsoletes=True, reponame=None, reports=False)\n"
+ "# :api"},
+ {"get_best_solution", (PyCFunction) get_best_solution,
+ METH_VARARGS | METH_KEYWORDS,
+ "get_best_solution(self, sack, with_nevra=True, with_provides=True, with_filenames=True,\n"
+ " forms=None, with_src=True, query=None)\n"
+ "# :api\n"
+ "Try to find first real solution for subject if it is NEVRA, provide or file name\n"
+ "return: dict with keys nevra and query"},
+ {NULL} /* sentinel */
+};
+
+PyTypeObject subject_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_hawkey.Subject", /*tp_name*/
+ sizeof(_SubjectObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor) subject_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ "Subject object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0,/* tp_iter */
+ 0, /* tp_iternext */
+ subject_methods, /* tp_methods */
+ 0, /* tp_members */
+ subject_getsetters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)subject_init, /* tp_init */
+ 0, /* tp_alloc */
+ subject_new, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SUBJECT_PY_H
+#define SUBJECT_PY_H
+
+#include "hy-subject.h"
+#include "hy-types.h"
+
+extern PyTypeObject subject_Type;
+
+#endif
--- /dev/null
+__pycache__/
--- /dev/null
+add_subdirectory(module)
+add_subdirectory(tests)
--- /dev/null
+if(${PYTHON_VERSION_MAJOR} STREQUAL "2")
+ set(TEST_MODULE_NAME "_hawkey_testmodule")
+else()
+ set(TEST_MODULE_NAME "_hawkey_test")
+endif()
+
+find_package(PythonInstDir)
+include_directories(${PYTHON_INCLUDE_PATH})
+include_directories(${CMAKE_SOURCE_DIR})
+link_directories("${CMAKE_SOURCE_DIR}/tests/hawkey")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-strict-aliasing")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-strict-aliasing")
+
+set(testmodule_SRCS
+ hawkey_testmodule.cpp
+)
+
+add_library(testmodule SHARED ${testmodule_SRCS})
+set_target_properties(testmodule PROPERTIES PREFIX "")
+set_target_properties(testmodule PROPERTIES OUTPUT_NAME ${TEST_MODULE_NAME})
+target_link_libraries(testmodule _hawkeymodule
+ testshared
+ ${PYTHON_LIBRARY}
+)
+
+# copy the whole package under hawkey/test so 'import hawkey.test' works as expected:
+set(pytest_COPIES __init__.py)
+set(TMODULE_TARGET ${CMAKE_BINARY_DIR}/python/hawkey/hawkey/test)
+file(COPY ${pytest_COPIES} DESTINATION ${TMODULE_TARGET})
+add_custom_command(TARGET testmodule
+ POST_BUILD
+ COMMAND cp $<TARGET_FILE:testmodule> ${TMODULE_TARGET}
+)
+
+install(FILES __init__.py DESTINATION ${PYTHON_INSTALL_DIR}/hawkey/test)
+install(TARGETS testmodule LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}/hawkey/test)
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import _hawkey_test
+
+import hawkey
+import os
+
+EXPECT_SYSTEM_NSOLVABLES = _hawkey_test.EXPECT_SYSTEM_NSOLVABLES
+EXPECT_MAIN_NSOLVABLES = _hawkey_test.EXPECT_MAIN_NSOLVABLES
+EXPECT_UPDATES_NSOLVABLES = _hawkey_test.EXPECT_UPDATES_NSOLVABLES
+EXPECT_YUM_NSOLVABLES = _hawkey_test.EXPECT_YUM_NSOLVABLES
+FIXED_ARCH = _hawkey_test.FIXED_ARCH
+UNITTEST_DIR = _hawkey_test.UNITTEST_DIR
+YUM_DIR_SUFFIX = _hawkey_test.YUM_DIR_SUFFIX
+
+glob_for_repofiles = _hawkey_test.glob_for_repofiles
+
+class TestSackMixin(object):
+ def __init__(self, repo_dir):
+ self.repo_dir = repo_dir
+
+ def load_test_repo(self, name, fn, system=False):
+ path = os.path.join(self.repo_dir, fn)
+ _hawkey_test.load_repo(self, name, path, system)
+
+ def load_system_repo(self, *args, **kwargs):
+ path = os.path.join(self.repo_dir, "@System.repo")
+ _hawkey_test.load_repo(self, hawkey.SYSTEM_REPO_NAME, path, True)
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <Python.h>
+
+// hawkey
+#include "dnf-sack-private.hpp"
+
+#include "python/hawkey/repo-py.hpp"
+#include "python/hawkey/sack-py.hpp"
+#include "tests/hawkey/testshared.h"
+
+#include "python/hawkey/pycomp.hpp"
+
+
+PYCOMP_MOD_INIT(_hawkey_test);
+
+static PyObject *
+py_load_repo(PyObject *unused, PyObject *args)
+{
+ PyObject *sack = NULL;
+ char *name = NULL, *path = NULL;
+ int installed;
+
+ if (!PyArg_ParseTuple(args, "Ossi", &sack, &name, &path, &installed))
+ return NULL;
+
+ DnfSack *csack = sackFromPyObject(sack);
+ if (csack == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected a DnfSack *object.");
+ return NULL;
+ }
+ if (load_repo(dnf_sack_get_pool(csack), name, path, installed)) {
+ PyErr_SetString(PyExc_IOError, "Can not load a testing repo.");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+py_glob_for_repofiles(PyObject *unused, PyObject *args)
+{
+ const char *repo_name, *path;
+ DnfSack *sack;
+
+ if (!PyArg_ParseTuple(args, "O&ss",
+ sack_converter, &sack, &repo_name, &path))
+ return NULL;
+ HyRepo repo = glob_for_repofiles(dnf_sack_get_pool(sack), repo_name, path);
+ return repoToPyObject(repo);
+}
+
+static struct PyMethodDef testmodule_methods[] = {
+ {"load_repo", (PyCFunction)py_load_repo,
+ METH_VARARGS, NULL},
+ {"glob_for_repofiles", (PyCFunction)py_glob_for_repofiles,
+ METH_VARARGS, NULL},
+ {NULL} /* sentinel */
+};
+
+PYCOMP_MOD_INIT(_hawkey_test)
+{
+ PyObject *m;
+ PYCOMP_MOD_DEF(m, "_hawkey_test", testmodule_methods);
+ if (!m)
+ return PYCOMP_MOD_ERROR_VAL;
+ PyModule_AddIntConstant(m, "EXPECT_SYSTEM_NSOLVABLES",
+ TEST_EXPECT_SYSTEM_NSOLVABLES);
+ PyModule_AddIntConstant(m, "EXPECT_MAIN_NSOLVABLES",
+ TEST_EXPECT_MAIN_NSOLVABLES);
+ PyModule_AddIntConstant(m, "EXPECT_UPDATES_NSOLVABLES",
+ TEST_EXPECT_UPDATES_NSOLVABLES);
+ PyModule_AddIntConstant(m, "EXPECT_YUM_NSOLVABLES",
+ TEST_EXPECT_YUM_NSOLVABLES);
+ PyModule_AddStringConstant(m, "FIXED_ARCH", TEST_FIXED_ARCH);
+ PyModule_AddStringConstant(m, "UNITTEST_DIR", UNITTEST_DIR);
+ PyModule_AddStringConstant(m, "YUM_DIR_SUFFIX", YUM_DIR_SUFFIX);
+
+ return PYCOMP_MOD_SUCCESS_VAL(m);
+}
--- /dev/null
+execute_process(COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" "${CMAKE_BINARY_DIR}/bindings/python" "${CMAKE_CURRENT_BINARY_DIR}/libdnf")
+add_test(NAME test_python3_libdnf COMMAND ${PYTHON_EXECUTABLE} -m unittest discover -t "${CMAKE_CURRENT_SOURCE_DIR}/.." -s "${CMAKE_CURRENT_SOURCE_DIR}")
+set_property(TEST test_python3_libdnf PROPERTY ENVIRONMENT
+ "PYTHONPATH=${CMAKE_BINARY_DIR}/python/hawkey/"
+ "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/libdnf/"
+)
--- /dev/null
+#
+# Copyright (C) 2012-2019 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from sys import version_info as python_version
+
+import libdnf
+import hawkey
+import hawkey.test
+import os
+import tempfile
+import unittest
+
+cachedir = None
+# inititialize the dir once and share it for all sacks within a single run
+if cachedir is None:
+ cachedir = tempfile.mkdtemp(dir=os.path.dirname(hawkey.test.UNITTEST_DIR),
+ prefix='pyhawkey')
+
+class TestCase(unittest.TestCase):
+ repo_dir = os.path.normpath(os.path.join(__file__, "../../../../../data/tests/hawkey/"))
+
+ def assertLength(self, collection, length):
+ return self.assertEqual(len(collection), length)
+
+ def assertItemsEqual(self, item1, item2):
+ # assertItemsEqual renamed in Python3
+ if python_version.major < 3:
+ super(TestCase, self).assertItemsEqual(item1, item2)
+ else:
+ super(TestCase, self).assertCountEqual(item1, item2)
+
+skip = unittest.skip
+
+class TestSack(hawkey.test.TestSackMixin, hawkey.Sack):
+ def __init__(self, repo_dir, PackageClass=None, package_userdata=None,
+ make_cache_dir=True, arch=None, all_arch=False):
+ hawkey.test.TestSackMixin.__init__(self, repo_dir)
+ hawkey.Sack.__init__(self,
+ cachedir=cachedir,
+ arch=arch if arch is not None else hawkey.test.FIXED_ARCH,
+ pkgcls=PackageClass,
+ pkginitval=package_userdata,
+ make_cache_dir=make_cache_dir,
+ all_arch=all_arch,
+ )
+
+ def load_repo(self, **kwargs):
+ d = os.path.join(self.repo_dir, 'yum/')
+ self._conf = libdnf.conf.ConfigMain()
+ repo_conf = libdnf.conf.ConfigRepo(self._conf)
+ self._conf.cachedir().set(libdnf.conf.Option.Priority_REPOCONFIG, self.cache_dir)
+ repo_conf.baseurl().set(libdnf.conf.Option.Priority_REPOCONFIG, 'file://%s' % d)
+ repo_conf.this.disown() # _repo will be the owner of _config
+ repo = libdnf.repo.Repo("messerk", repo_conf)
+ repo.load()
+ super(TestSack, self).load_repo(repo, **kwargs)
+
+ # Loading using hawkey.Repo
+ def load_repo_hawkey_Repo(self, **kwargs):
+ d = os.path.join(self.repo_dir, hawkey.test.YUM_DIR_SUFFIX)
+ repo = hawkey.test.glob_for_repofiles(self, "messerk", d)
+ super(TestSack, self).load_repo(repo, **kwargs)
+
+def by_name(sack, name):
+ return hawkey.Query(sack).filter(name=name)[0]
+
+def by_name_repo(sack, name, repo):
+ return hawkey.Query(sack).filter(name=name, reponame=repo)[0]
--- /dev/null
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+"""Tests of the _hawkey.Advisory class."""
+
+from __future__ import absolute_import
+from __future__ import unicode_literals
+from . import base
+
+import datetime
+import hawkey
+import itertools
+import time
+
+def find_advisory(sack, id_):
+ """Find an advisory with given ID."""
+ # The function is needed because advisories cannot be retrieved directly.
+ advisories_iterable = itertools.chain(
+ (pkg.get_advisories(hawkey.LT) for pkg in hawkey.Query(sack)),
+ (pkg.get_advisories(hawkey.GT | hawkey.EQ) for pkg in hawkey.Query(sack)))
+ for advisory in itertools.chain.from_iterable(advisories_iterable):
+ if advisory.id == id_:
+ return advisory
+
+class Test(base.TestCase):
+ """Test case consisting of one random advisory."""
+
+ def setUp(self):
+ """Prepare the test fixture."""
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_repo(load_updateinfo=True)
+ self.advisory = find_advisory(sack, 'FEDORA-2008-9969')
+
+ def test_description(self):
+ self.assertEqual(self.advisory.description, 'An example update to the tour package.')
+
+ def test_packages(self):
+ filenames = [apkg.filename for apkg in self.advisory.packages]
+ self.assertEqual(filenames, ['tour.noarch.rpm'])
+
+ def test_id(self):
+ self.assertEqual(self.advisory.id, 'FEDORA-2008-9969')
+
+ def test_references(self):
+ urls = [ref.url for ref in self.advisory.references]
+ self.assertEqual(urls,
+ ['https://bugzilla.redhat.com/show_bug.cgi?id=472090',
+ 'https://bugzilla.gnome.com/show_bug.cgi?id=472091'])
+
+ def test_rights(self):
+ self.assertIsNone(self.advisory.rights)
+
+ def test_title(self):
+ self.assertEqual(self.advisory.title, 'lvm2-2.02.39-7.fc10')
+
+ def test_type(self):
+ self.assertEqual(self.advisory.type, hawkey.ADVISORY_BUGFIX)
+
+ def test_updated(self):
+ self.assertEqual(self.advisory.updated,
+ datetime.datetime(2008, 12, 9, 11, 31, 26) -
+ datetime.timedelta(seconds=time.timezone))
--- /dev/null
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+"""Tests of the _hawkey.AdvisoryPkg class."""
+
+from __future__ import absolute_import
+from __future__ import unicode_literals
+from . import base
+
+import hawkey
+import itertools
+
+def find_apackage(sack, filename):
+ """Find an advisory package with given file name."""
+ # The function is needed because packages cannot be retrieved directly.
+ advisories_iterable = itertools.chain(
+ (pkg.get_advisories(hawkey.LT) for pkg in hawkey.Query(sack)),
+ (pkg.get_advisories(hawkey.GT | hawkey.EQ) for pkg in hawkey.Query(sack)))
+ advisories = itertools.chain.from_iterable(advisories_iterable)
+ apackages_iterable = (advisory.packages for advisory in advisories)
+ for apackage in itertools.chain.from_iterable(apackages_iterable):
+ if apackage.filename == filename:
+ return apackage
+
+class Test(base.TestCase):
+ """Test case consisting of one random advisory package."""
+
+ def setUp(self):
+ """Prepare the test fixture."""
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_repo(load_updateinfo=True)
+ self.apackage = find_apackage(self.sack, 'tour.noarch.rpm')
+
+ def test_name(self):
+ self.assertEqual(self.apackage.name, 'tour')
+
+ def test_evr(self):
+ self.assertEqual(self.apackage.evr, '4-7')
+
+ def test_arch(self):
+ self.assertEqual(self.apackage.arch, 'noarch')
+
+ def test_filename(self):
+ self.assertEqual(self.apackage.filename, 'tour.noarch.rpm')
--- /dev/null
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+"""Tests of the _hawkey.AdvisoryRef class."""
+
+from __future__ import absolute_import
+from __future__ import unicode_literals
+from . import base
+
+import hawkey
+import itertools
+
+def find_reference(sack, url):
+ """Find an advisory reference with given URL."""
+ # The function is needed because references cannot be retrieved directly.
+ advisories_iterable = itertools.chain(
+ (pkg.get_advisories(hawkey.LT) for pkg in hawkey.Query(sack)),
+ (pkg.get_advisories(hawkey.GT | hawkey.EQ) for pkg in hawkey.Query(sack)))
+ advisories = itertools.chain.from_iterable(advisories_iterable)
+ references_iterable = (advisory.references for advisory in advisories)
+ for reference in itertools.chain.from_iterable(references_iterable):
+ if reference.url == url:
+ return reference
+
+class Test(base.TestCase):
+ """Test case consisting of one random advisory reference."""
+
+ def setUp(self):
+ """Prepare the test fixture."""
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_repo(load_updateinfo=True)
+ self.reference = find_reference(
+ sack, 'https://bugzilla.redhat.com/show_bug.cgi?id=472090')
+
+ def test_type(self):
+ self.assertEqual(self.reference.type, hawkey.REFERENCE_BUGZILLA)
+
+ def test_id(self):
+ self.assertEqual(self.reference.id, '472090')
+
+ def test_title(self):
+ self.assertEqual(self.reference.title,
+ '/etc/init.d/clvmd points to /usr/sbin for LVM tools')
+
+ def test_url(self):
+ self.assertEqual(self.reference.url,
+ 'https://bugzilla.redhat.com/show_bug.cgi?id=472090')
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import base
+from copy import deepcopy
+
+import hawkey
+
+class GoalTest(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.sack.load_test_repo("main", "main.repo")
+
+ def test_actions(self):
+ sltr = hawkey.Selector(self.sack).set(name="walrus")
+ goal = hawkey.Goal(self.sack)
+
+ self.assertEqual(0, goal.actions & (hawkey.ERASE | hawkey.DISTUPGRADE |
+ hawkey.DISTUPGRADE_ALL | hawkey.DOWNGRADE | hawkey.INSTALL | hawkey.UPGRADE |
+ hawkey.UPGRADE_ALL))
+ goal.upgrade(select=sltr)
+ self.assertEqual(hawkey.UPGRADE, goal.actions)
+
+ def test_clone(self):
+ pkg = base.by_name(self.sack, "penny-lib")
+ goal = hawkey.Goal(self.sack)
+ goal.erase(pkg)
+ self.assertFalse(goal.run())
+
+ goal2 = deepcopy(goal)
+ self.assertTrue(goal2.run(allow_uninstall=True))
+ self.assertEqual(len(goal2.list_erasures()), 2)
+
+ goal3 = deepcopy(goal)
+ goal3.add_protected(hawkey.Query(self.sack).filter(name="flying"))
+ self.assertFalse(goal3.run(allow_uninstall=True))
+
+ def test_list_err(self):
+ goal = hawkey.Goal(self.sack)
+ self.assertRaises(hawkey.ValueException, goal.list_installs)
+
+ def test_empty_selector(self):
+ sltr = hawkey.Selector(self.sack)
+ goal = hawkey.Goal(self.sack)
+ # does not raise ValueException
+ goal.install(select=sltr)
+ goal.run()
+ self.assertEqual(goal.list_installs(), [])
+
+ def test_install_selector(self):
+ sltr = hawkey.Selector(self.sack).set(name="walrus")
+ # without checking versioning, the update is accepted:
+ self.assertIsNone(hawkey.Goal(self.sack).upgrade(select=sltr))
+
+ def test_install_selector_weak(self):
+ sltr = hawkey.Selector(self.sack).set(name='hello')
+ goal = hawkey.Goal(self.sack)
+ goal.install(select=sltr, optional=True)
+ self.assertTrue(goal.run())
+
+ def test_install_selector_err(self):
+ sltr = hawkey.Selector(self.sack)
+ self.assertRaises(hawkey.ValueException, sltr.set, undefined="eapoe")
+
+ def test_reinstall(self):
+ inst = base.by_name_repo(self.sack, "fool", hawkey.SYSTEM_REPO_NAME)
+ avail = base.by_name_repo(self.sack, "fool", "main")
+ goal = hawkey.Goal(self.sack)
+ goal.install(avail)
+ self.assertTrue(goal.run())
+ self.assertLength(goal.list_erasures(), 0)
+ self.assertLength(goal.list_installs(), 0)
+ self.assertLength(goal.list_reinstalls(), 1)
+ reinstall = goal.list_reinstalls()[0]
+ obsoleted = goal.obsoleted_by_package(reinstall)
+ self.assertItemsEqual(list(map(str, obsoleted)), ("fool-1-3.noarch", ))
+
+ def test_req(self):
+ goal = hawkey.Goal(self.sack)
+ self.assertEqual(goal.req_length(), 0)
+ self.assertFalse(goal.req_has_erase())
+ sltr = hawkey.Selector(self.sack).set(name="jay")
+ goal.erase(select=sltr)
+ self.assertEqual(goal.req_length(), 1)
+ self.assertTrue(goal.req_has_erase())
+
+ goal = hawkey.Goal(self.sack)
+ goal.upgrade(select=sltr)
+ self.assertFalse(goal.req_has_erase())
+
+ goal = hawkey.Goal(self.sack)
+ pkg = hawkey.Query(self.sack).filter(name="dog")[0]
+ goal.erase(pkg, clean_deps=True)
+ self.assertTrue(goal.req_has_erase())
+
+
+class GoalRunAll(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.sack.load_test_repo("greedy", "greedy.repo")
+ self.goal = hawkey.Goal(self.sack)
+
+ def test_goal_install_weak_deps(self):
+ pkg_b = base.by_name(self.sack, "B")
+ self.goal.install(pkg_b)
+ self.assertTrue(self.goal.run())
+ installs = self.goal.list_installs()
+ self.assertEqual(len(installs), 2)
+ expected_installs = ("B-1-0.noarch", "C-1-0.noarch")
+ self.assertItemsEqual(list(map(str, installs)), expected_installs)
+ goal2 = deepcopy(self.goal)
+ self.assertTrue(goal2.run(ignore_weak_deps=True))
+ installs2 = goal2.list_installs()
+ self.assertEqual(len(goal2.list_installs()), 1)
+ self.assertEqual(str(installs2[0]), "B-1-0.noarch")
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import hawkey
+import unittest
+
+
+class NEVRATest(unittest.TestCase):
+ def test_evr_cmp(self):
+ sack = hawkey.Sack()
+ n1 = hawkey.split_nevra("jay-3:3.10-4.fc3.x86_64")
+ n2 = hawkey.split_nevra("jay-4.10-4.fc3.x86_64")
+ self.assertGreater(n1.evr_cmp(n2, sack), 0)
+ self.assertLess(n2.evr_cmp(n1, sack), 0)
+
+ n1 = hawkey.split_nevra("jay-3.10-4.fc3.x86_64")
+ n2 = hawkey.split_nevra("jay-3.10-5.fc3.x86_64")
+ self.assertLess(n1.evr_cmp(n2, sack), 0)
+
+ n1 = hawkey.split_nevra('pungi-4.0.14-3.fc24.src')
+ n2 = hawkey.split_nevra('pungi-4.0.7-1.fc24.src')
+ self.assertFalse(n1 < n2)
--- /dev/null
+#
+# Copyright (C) 2012-2014 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import base
+from sys import version_info as python_version
+
+import hawkey
+
+class AdvisoriesTest(base.TestCase):
+ """Tests related to packages and updateinfo metadata."""
+
+ def setUp(self):
+ """Prepare the test fixture."""
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_repo(load_updateinfo=True)
+
+ def test(self):
+ pkg = hawkey.Query(self.sack).filter(name='tour')[0]
+ advisories = pkg.get_advisories(hawkey.GT)
+ self.assertEqual(len(advisories), 1)
+ self.assertEqual(advisories[0].id, u'FEDORA-2008-9969')
+
+ def test_noadvisory(self):
+ pkg = hawkey.Query(self.sack).filter(name='mystery-devel')[0]
+ advisories = pkg.get_advisories(hawkey.GT)
+ self.assertEqual(len(advisories), 0)
+
+class PackageTest(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ q = hawkey.Query(self.sack).filter(name__eq="flying")
+ self.pkg = list(q)[0]
+
+ def test_instance(self):
+ self.assertTrue(isinstance(self.pkg, hawkey.Package))
+
+ def test_repr(self):
+ regexp = r"<hawkey.Package object id \d+, flying-2-9\.noarch, @System>"
+ self.assertRegex(repr(self.pkg), regexp)
+
+ def test_str(self):
+ self.assertEqual(str(self.pkg),
+ "flying-2-9.noarch")
+
+ def test_hashability(self):
+ """ Test that hawkey.Package objects are hashable.
+
+ So they can be keys in a dict.
+ """
+ d = {}
+ d[self.pkg] = True
+ pkg2 = hawkey.Query(self.sack).filter(name__eq="fool").run()[0]
+ d[pkg2] = 1
+ self.assertEqual(len(d), 2)
+
+ # if we get the same package twice it is a different object (hawkey does
+ # not pool Packages at this time). It however compares equal.
+ pkg3 = hawkey.Query(self.sack).filter(name__eq="fool").run()[0]
+ self.assertIsNot(pkg2, pkg3)
+ self.assertEqual(pkg2, pkg3)
+ d[pkg3] += 1
+ self.assertEqual(d[pkg2], 2)
+ self.assertEqual(len(d), 2)
+
+ def test_conflicts(self):
+ pkg = base.by_name(self.sack, 'dog')
+ self.assertItemsEqual(list(map(str, pkg.conflicts)), ('custard = 1.1',))
+
+ def test_files(self):
+ pkg = base.by_name(self.sack, 'fool')
+ self.assertSequenceEqual(pkg.files, ('/no/answers',))
+
+class PackageCmpTest(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.sack.load_test_repo("main", "main.repo")
+ self.pkg1 = base.by_name_repo(self.sack, "fool", hawkey.SYSTEM_REPO_NAME)
+
+ def test_cmp(self):
+ pkg2 = base.by_name_repo(self.sack, "fool", "main")
+ # if nevra matches the packages are equal:
+ self.assertEqual(self.pkg1, pkg2)
+
+ # if the name doesn't match they are not equal:
+ pkg2 = base.by_name_repo(self.sack, "hello", "main")
+ self.assertNotEqual(self.pkg1, pkg2)
+
+ # if nevr matches, but not arch, they are not equal:
+ pkg1 = hawkey.split_nevra("semolina-2-0.x86_64").to_query(self.sack)[0]
+ pkg2 = hawkey.split_nevra("semolina-2-0.i686").to_query(self.sack)[0]
+ self.assertNotEqual(pkg1, pkg2)
+ # however evr_cmp compares only the evr part:
+ self.assertEqual(pkg1.evr_cmp(pkg2), 0)
+
+ pkg1 = hawkey.split_nevra("jay-6.0-0.x86_64").to_query(self.sack)[0]
+ pkg2 = hawkey.split_nevra("jay-5.0-0.x86_64").to_query(self.sack)[0]
+ self.assertLess(pkg2, pkg1)
+ self.assertGreater(pkg1.evr_cmp(pkg2), 0)
+
+ def test_cmp_fail(self):
+ # should not throw TypeError
+ self.assertNotEqual(self.pkg1, "hawkey-package")
+ self.assertNotEqual(self.pkg1, self.sack)
+
+ if python_version.major > 3:
+ self.assertRaises(TypeError, lambda: self.pkg1 <= "hawkey-package")
+
+ def test_cmp_lt(self):
+ greater_package = base.by_name_repo(self.sack, "hello", "main")
+
+ self.assertLess(self.pkg1, greater_package)
+
+ def test_cmp_gt(self):
+ less_package = base.by_name_repo(self.sack, "baby", "main")
+
+ self.assertGreater(self.pkg1, less_package)
+
+class ChecksumsTest(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_repo()
+ self.pkg = hawkey.Query(self.sack).filter(name="mystery-devel")[0]
+
+ def test_checksum(self):
+ (chksum_type, chksum) = self.pkg.chksum
+ self.assertEqual(len(chksum), 32)
+ if python_version.major < 3:
+ self.assertEqual(chksum[0], b'\x2e')
+ self.assertEqual(chksum[31], b'\xf5')
+ else:
+ self.assertEqual(chksum[0], 0x2e)
+ self.assertEqual(chksum[31], 0xf5)
+ self.assertEqual(chksum_type, hawkey.CHKSUM_SHA256)
+
+ def test_checksum_fail(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_system_repo()
+ pkg = base.by_name(sack, "fool")
+ self.assertIsNone(pkg.chksum)
+ self.assertIsNone(pkg.hdr_chksum)
+
+ def test_sizes(self):
+ pkg = base.by_name(self.sack, "mystery-devel")
+ self.assertEqual(pkg.installsize, 59)
+ self.assertEqual(pkg.downloadsize, 2329)
+
+class FullPropertiesTest(base.TestCase):
+ """Tests properties as seen in a real primary.xml."""
+
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_repo()
+ self.pkg = hawkey.Query(self.sack).filter(name="mystery-devel")[0]
+
+ def test_baseurl(self):
+ self.assertEqual(self.pkg.baseurl, 'disagree')
+
+ def test_hdr_end(self):
+ self.assertEqual(self.pkg.hdr_end, 2081)
+
+ def test_sourcerpm(self):
+ self.assertEqual(self.pkg.sourcerpm, 'mystery-19.67-1.src.rpm')
--- /dev/null
+#
+# Copyright (C) 2012-2014 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import base
+
+import hawkey
+import sys
+import unittest
+
+class TestQuery(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+
+ def test_sanity(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__eq="flying")
+ self.assertEqual(q.count(), 1)
+
+ def test_creation_empty_sack(self):
+ s = hawkey.Sack(make_cache_dir=True)
+ q = hawkey.Query(s)
+
+ def test_exception(self):
+ q = hawkey.Query(self.sack)
+ self.assertRaises(hawkey.ValueException, q.filter, flying__eq="name")
+ self.assertRaises(hawkey.ValueException, q.filter, flying="name")
+
+ def test_unicode(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__eq=u"flying")
+ self.assertEqual(q.count(), 1)
+
+ q = hawkey.Query(self.sack)
+ q.filterm(name__eq=[u"flying", "penny"])
+ self.assertEqual(q.count(), 2)
+
+ def test_count(self):
+ q = hawkey.Query(self.sack).filter(name=["flying", "penny"])
+ self.assertEqual(len(q), 2)
+ self.assertEqual(len(q), q.count())
+ self.assertTrue(q)
+
+ q = hawkey.Query(self.sack).filter(name="naturalE")
+ self.assertFalse(q)
+ self.assertEqual(len(q.run()), 0)
+
+ def test_kwargs_check(self):
+ q = hawkey.Query(self.sack)
+ self.assertRaises(hawkey.ValueException, q.filter, name="flying", upgrades="maracas")
+
+ def test_kwargs(self):
+ q = hawkey.Query(self.sack)
+ # test combining several criteria
+ q.filterm(name__glob="*enny*", summary__substr="eyes")
+ self.assertEqual(q.count(), 1)
+ # test shortcutting for equality comparison type
+ q = hawkey.Query(self.sack)
+ q.filterm(name="flying")
+ self.assertEqual(q.count(), 1)
+ # test flags parsing
+ q = hawkey.Query(self.sack).filter(name="FLYING")
+ self.assertEqual(q.count(), 0)
+ q = hawkey.Query(self.sack).filter(hawkey.ICASE, name="FLYING")
+ self.assertEqual(q.count(), 1)
+
+ def test_in(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__substr=["ool", "enny-li"])
+ self.assertEqual(q.count(), 2)
+
+ def test_in_set(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__substr=set(["ool", "enny-li"]))
+ self.assertEqual(q.count(), 2)
+
+ def test_iteration(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__substr=["penny"])
+ self.assertEqual(q.count(), 2)
+ self.assertNotEqual(q[0], q[1])
+
+ def test_clone(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__substr=["penny"])
+ q_clone = hawkey.Query(query=q)
+ del q
+
+ self.assertEqual(q_clone.count(), 2)
+ self.assertNotEqual(q_clone[0], q_clone[1])
+
+ def test_clone_with_evaluation(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name__substr="penny")
+ q.run()
+ q_clone = hawkey.Query(query=q)
+ del q
+ self.assertTrue(q_clone.evaluated)
+ self.assertLength(q_clone.run(), 2)
+
+ def test_immutability(self):
+ q = hawkey.Query(self.sack).filter(name="jay")
+ q2 = q.filter(evr="5.0-0")
+ self.assertEqual(q.count(), 2)
+ self.assertEqual(q2.count(), 1)
+
+ def test_copy_lazyness(self):
+ q = hawkey.Query(self.sack).filter(name="jay")
+ self.assertLength(q.run(), 2)
+ q2 = q.filter(evr="5.0-0")
+ self.assertLength(q2.run(), 1)
+
+ def test_empty(self):
+ q = hawkey.Query(self.sack).filter(empty=True)
+ self.assertLength(q, 0)
+ q = hawkey.Query(self.sack)
+ self.assertRaises(hawkey.ValueException, q.filter, empty=False)
+
+ def test_epoch(self):
+ q = hawkey.Query(self.sack).filter(epoch__gt=4)
+ self.assertEqual(len(q), 1)
+ self.assertEqual(q[0].epoch, 6)
+
+ def test_version(self):
+ q = hawkey.Query(self.sack).filter(version__gte="5.0")
+ self.assertEqual(len(q), 3)
+ q = hawkey.Query(self.sack).filter(version__glob="1.2*")
+ self.assertLength(q, 2)
+
+ def test_package_in(self):
+ pkgs = list(hawkey.Query(self.sack).filter(name=["flying", "penny"]))
+ q = hawkey.Query(self.sack).filter(pkg=pkgs)
+ self.assertEqual(len(q), 2)
+ q2 = q.filter(version__gt="3")
+ self.assertEqual(len(q2), 1)
+
+ def test_nevra_match(self):
+ query = hawkey.Query(self.sack).filter(nevra__glob="*lib*64")
+ self.assertEqual(len(query), 1)
+ self.assertEqual(str(query[0]), "penny-lib-4-1.x86_64")
+
+ def test_nevra_strict_match(self):
+ query = hawkey.Query(self.sack).filter(nevra_strict="penny-lib-4-1.x86_64")
+ self.assertEqual(len(query), 1)
+ self.assertEqual(str(query[0]), "penny-lib-4-1.x86_64")
+
+ def test_nevra_strict_list_match(self):
+ query = hawkey.Query(self.sack).filter(nevra_strict=["penny-lib-4-1.x86_64"])
+ self.assertEqual(len(query), 1)
+ self.assertEqual(str(query[0]), "penny-lib-4-1.x86_64")
+
+ def test_nevra_strict_epoch0_match(self):
+ query = hawkey.Query(self.sack).filter(nevra_strict="penny-lib-0:4-1.x86_64")
+ self.assertEqual(len(query), 1)
+ self.assertEqual(str(query[0]), "penny-lib-4-1.x86_64")
+
+ def test_repeated(self):
+ q = hawkey.Query(self.sack).filter(name="jay")
+ q.filterm(latest_per_arch=True)
+ self.assertEqual(len(q), 1)
+
+ def test_latest(self):
+ q = hawkey.Query(self.sack).filter(name="pilchard")
+ q.filterm(latest_per_arch=True)
+ self.assertEqual(len(q), 2)
+ q.filterm(latest=True)
+ self.assertEqual(len(q), 2)
+
+ def test_reldep(self):
+ flying = base.by_name(self.sack, "flying")
+ requires = flying.requires
+ q = hawkey.Query(self.sack).filter(provides=requires[0])
+ self.assertEqual(len(q), 1)
+ self.assertEqual(str(q[0]), "penny-lib-4-1.x86_64")
+ self.assertRaises(hawkey.QueryException, q.filter, provides__gt=requires[0])
+
+ q = hawkey.Query(self.sack).filter(provides="thisisnotgoingtoexist")
+ self.assertLength(q.run(), 0)
+
+ def test_reldep_list(self):
+ self.sack.load_test_repo("updates", "updates.repo")
+ fool = base.by_name_repo(self.sack, "fool", "updates")
+ q = hawkey.Query(self.sack).filter(provides=fool.obsoletes)
+ self.assertEqual(str(q.run()[0]), "penny-4-1.noarch")
+
+ def test_disabled_repo(self):
+ self.sack.disable_repo(hawkey.SYSTEM_REPO_NAME)
+ q = hawkey.Query(self.sack).filter(name="jay")
+ self.assertLength(q.run(), 0)
+ self.sack.enable_repo(hawkey.SYSTEM_REPO_NAME)
+ q = hawkey.Query(self.sack).filter(name="jay")
+ self.assertLength(q.run(), 2)
+
+ def test_multiple_flags(self):
+ q = hawkey.Query(self.sack).filter(name__glob__not=["p*", "j*"])
+ self.assertItemsEqual(list(map(lambda p: p.name, q.run())),
+ ["baby", "bloop", "dog", "flying", "fool", "gun", "tour"])
+
+ def test_apply(self):
+ q = hawkey.Query(self.sack).filter(name__glob__not="p*").apply()
+ res = q.filter(name__glob__not="j*").run()
+ self.assertItemsEqual(list(map(lambda p: p.name, res)),
+ ["baby", "bloop", "dog", "flying", "fool", "gun", "tour"])
+
+ def test_provides_glob_should_work(self):
+ q1 = hawkey.Query(self.sack).filter(provides__glob="penny*")
+ self.assertLength(q1, 2)
+ q2 = hawkey.Query(self.sack).filter(provides__glob="*")
+ q3 = hawkey.Query(self.sack).filter()
+ self.assertEqual(len(q2), len(q3))
+ q4 = hawkey.Query(self.sack).filter(provides__glob="P-l*b >= 3")
+ self.assertLength(q4, 1)
+
+ def test_provides_glob_should_not_work(self):
+ q = hawkey.Query(self.sack).filter(provides="*")
+ self.assertLength(q, 0)
+ q = hawkey.Query(self.sack).filter(provides__glob="nomatch*")
+ self.assertLength(q, 0)
+
+ def test_provides_list_of_strings(self):
+ q1 = hawkey.Query(self.sack).filter(provides=["penny", "P-lib"])
+ q2 = hawkey.Query(self.sack).filter(provides__glob=["penny", "P-lib"])
+ self.assertEqual(len(q1), len(q2))
+ q3 = hawkey.Query(self.sack).filter(provides__glob=["penny*", "P-lib*"])
+ self.assertEqual(len(q1), len(q3))
+ q4 = hawkey.Query(self.sack).filter(provides__glob=["nomatch*", "P-lib*"])
+ q5 = hawkey.Query(self.sack).filter(provides__glob="P-lib*")
+ self.assertEqual(len(q4), len(q5))
+ q6 = hawkey.Query(self.sack).filter(provides=["nomatch", "P-lib"])
+ q7 = hawkey.Query(self.sack).filter(provides="P-lib")
+ self.assertEqual(len(q6), len(q7))
+ q8 = hawkey.Query(self.sack).filter(provides=[])
+ self.assertLength(q8, 0)
+ q9 = hawkey.Query(self.sack).filter(provides__glob=[])
+ self.assertLength(q9, 0)
+
+ def test_requires_list_of_strings(self):
+ q1 = hawkey.Query(self.sack).filter(requires=["penny", "P-lib"])
+ q2 = hawkey.Query(self.sack).filter(requires__glob=["penny", "P-lib"])
+ self.assertEqual(len(q1), len(q2))
+ q3 = hawkey.Query(self.sack).filter(requires__glob=["penny*", "P-lib*"])
+ self.assertEqual(len(q1), len(q3))
+ q4 = hawkey.Query(self.sack).filter(requires__glob=["nomatch*", "P-lib*"])
+ q5 = hawkey.Query(self.sack).filter(requires__glob="P-lib*")
+ self.assertEqual(len(q4), len(q5))
+ q6 = hawkey.Query(self.sack).filter(requires=["nomatch", "P-lib"])
+ q7 = hawkey.Query(self.sack).filter(requires="P-lib")
+ self.assertEqual(len(q6), len(q7))
+ q1 = hawkey.Query(self.sack).filter(requires__glob=["*bin/away"])
+ self.assertLength(q1, 1)
+
+
+class TestQueryAllRepos(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.sack.load_test_repo("main", "main.repo")
+ self.sack.load_test_repo("updates", "updates.repo")
+
+ def test_requires(self):
+ reldep = hawkey.Reldep(self.sack, "semolina = 2")
+ q = hawkey.Query(self.sack).filter(requires=reldep)
+ self.assertItemsEqual(list(map(str, q.run())),
+ ["walrus-2-5.noarch", "walrus-2-6.noarch"])
+
+ reldep = hawkey.Reldep(self.sack, "semolina > 1.0")
+ q = hawkey.Query(self.sack).filter(requires=reldep)
+ self.assertItemsEqual(list(map(str, q.run())),
+ ["walrus-2-5.noarch", "walrus-2-6.noarch"])
+
+ def test_obsoletes(self):
+ reldep = hawkey.Reldep(self.sack, "penny < 4-0")
+ q = hawkey.Query(self.sack).filter(obsoletes=reldep)
+ self.assertItemsEqual(list(map(str, q.run())), ["fool-1-5.noarch"])
+
+ def test_downgradable(self):
+ query = hawkey.Query(self.sack).filter(downgradable=True)
+ self.assertEqual({str(pkg) for pkg in query},
+ {"baby-6:5.0-11.x86_64", "jay-5.0-0.x86_64"})
+
+ def test_rco_glob(self):
+ q1 = hawkey.Query(self.sack).filter(requires__glob="*")
+ self.assertLength(q1, 12)
+ q2 = hawkey.Query(self.sack).filter(requires="*")
+ self.assertLength(q2, 0)
+ q3 = hawkey.Query(self.sack).filter(conflicts__glob="cu*")
+ self.assertLength(q3, 3)
+ q1 = hawkey.Query(self.sack).filter(obsoletes__glob="*")
+ self.assertLength(q1, 1)
+ q1 = hawkey.Query(self.sack).filter(recommends__glob="*")
+ self.assertLength(q1, 1)
+ q1 = hawkey.Query(self.sack).filter(enhances__glob="*")
+ self.assertLength(q1, 1)
+ q1 = hawkey.Query(self.sack).filter(suggests__glob="*")
+ self.assertLength(q1, 1)
+ q1 = hawkey.Query(self.sack).filter(supplements__glob="*")
+ self.assertLength(q1, 1)
+ q1 = hawkey.Query(self.sack).filter(requires__glob="*bin/away")
+ self.assertLength(q1, 1)
+
+
+class TestQueryUpdates(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.sack.load_test_repo("updates", "updates.repo")
+
+ def test_upgradable(self):
+ query = hawkey.Query(self.sack).filter(upgradable=True)
+ self.assertEqual({str(pkg) for pkg in query},
+ {"bloop-1.0-1.noarch", "dog-1-1.x86_64",
+ "flying-2-9.noarch", "fool-1-3.noarch",
+ "pilchard-1.2.3-1.i686", "pilchard-1.2.3-1.x86_64"})
+
+ def test_updates_noarch(self):
+ q = hawkey.Query(self.sack)
+ q.filterm(name="flying", upgrades=1)
+ self.assertEqual(q.count(), 3)
+
+ def test_updates_arch(self):
+ q = hawkey.Query(self.sack)
+ pilchard = q.filter(name="dog", upgrades=True)
+ self.assertItemsEqual(list(map(str, pilchard.run())), ["dog-1-2.x86_64"])
+
+ def test_glob_arch(self):
+ q = hawkey.Query(self.sack)
+ pilchard = q.filter(name="pilchard", version="1.2.4", release="1",
+ arch__glob="*6*")
+ res = list(map(str, pilchard.run()))
+ self.assertItemsEqual(res, ["pilchard-1.2.4-1.x86_64",
+ "pilchard-1.2.4-1.i686"])
+
+ def test_obsoletes(self):
+ q = hawkey.Query(self.sack).filter(name="penny")
+ o = hawkey.Query(self.sack)
+ self.assertRaises(hawkey.QueryException, o.filter, obsoletes__gt=q)
+
+ o = hawkey.Query(self.sack).filter(obsoletes=q)
+ self.assertLength(o, 1)
+ self.assertEqual(str(o[0]), "fool-1-5.noarch")
+
+ def test_requires_with_query(self):
+ q = hawkey.Query(self.sack).filter(name="fool")
+ o = hawkey.Query(self.sack).filter(requires=q)
+ self.assertLength(o, 1)
+ self.assertEqual(str(o[0]), "walrus-2-6.noarch")
+
+ def test_requires_with_package_list(self):
+ q = hawkey.Query(self.sack).filter(name="fool")
+ o = hawkey.Query(self.sack).filter(requires=q.run())
+ self.assertLength(o, 1)
+ self.assertEqual(str(o[0]), "walrus-2-6.noarch")
+
+ def test_subquery_evaluated(self):
+ q = hawkey.Query(self.sack).filter(name="penny")
+ self.assertFalse(q.evaluated)
+ self.assertLength(q.run(), 1)
+ self.assertTrue(q.evaluated)
+ o = hawkey.Query(self.sack).filter(obsoletes=q)
+ self.assertTrue(q.evaluated)
+ self.assertLength(q.run(), 1)
+ self.assertLength(o, 1)
+
+class TestOddArch(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_test_repo("ppc", "ppc.repo")
+
+ def test_latest(self):
+ q = hawkey.Query(self.sack).filter(latest=True)
+ self.assertEqual(len(q), 1)
+
+ q = hawkey.Query(self.sack).filter(latest_per_arch=True)
+ self.assertEqual(len(q), 1)
+
+
+class TestAllArch(base.TestCase):
+
+ def setUp(self):
+ self.sack1 = base.TestSack(repo_dir=self.repo_dir, arch="ppc64")
+ self.sack2 = base.TestSack(repo_dir=self.repo_dir, arch="x86_64")
+ self.sack3 = base.TestSack(repo_dir=self.repo_dir, all_arch=True)
+ self.sack1.load_test_repo("test_ppc", "ppc.repo")
+ self.sack2.load_test_repo("test_ppc", "ppc.repo")
+ self.sack3.load_test_repo("test_ppc", "ppc.repo")
+
+ def test_provides_all_arch_query(self):
+ # Reldep objects are per-sack, queries across are disallowed. So
+ # it is necessary to create 3 queries below.
+ #
+ # See "query-py: Ensure reldep is from the same sack" for details
+ ppc_pkgs_1 = hawkey.Query(self.sack1)
+ ppc_pkgs_2 = hawkey.Query(self.sack2)
+ ppc_pkgs_3 = hawkey.Query(self.sack3)
+ self.assertGreater(len(ppc_pkgs_1), 0)
+ pkg1 = ppc_pkgs_1[0]
+ pkg2 = ppc_pkgs_2[0]
+ pkg3 = ppc_pkgs_3[0]
+
+ query_ppc = hawkey.Query(self.sack1).filter(provides=pkg1.provides[0])
+ query_x86 = hawkey.Query(self.sack2).filter(provides=pkg2.provides[0])
+ query_all = hawkey.Query(self.sack3).filter(provides=pkg3.provides[0])
+
+ self.assertEqual(len(query_ppc), 1)
+ self.assertEqual(len(query_x86), 0)
+ self.assertEqual(len(query_all), 1)
+
+
+class TestQuerySubclass(base.TestCase):
+ class CustomQuery(hawkey.Query):
+ pass
+
+ def test_instance(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ q = self.CustomQuery(sack)
+ self.assertIsInstance(q, self.CustomQuery)
+ q = q.filter(name="pepper")
+ self.assertIsInstance(q, self.CustomQuery)
+
+class TestQueryFilterAdvisory(base.TestCase):
+ """Tests related to packages and updateinfo metadata."""
+
+ def setUp(self):
+ """Prepare the test fixture."""
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_repo(load_updateinfo=True)
+ self.expected_pkgs = hawkey.Query(self.sack).filter(nevra=[
+ "mystery-devel-19.67-1.noarch",
+ "tour-4-6.noarch"]
+ ).run()
+
+ def test_advisory(self):
+ pkgs = hawkey.Query(self.sack).filter(advisory="BEATLES-1967-1127").run()
+ self.assertEqual(pkgs, self.expected_pkgs)
+
+ def test_advisory_type(self):
+ pkgs = hawkey.Query(self.sack).filter(advisory_type="security").run()
+ self.assertEqual(pkgs, self.expected_pkgs)
+
+ def test_advisory_bug(self):
+ pkgs = hawkey.Query(self.sack).filter(advisory_bug="0#paul").run()
+ self.assertEqual(pkgs, self.expected_pkgs)
+
+ def test_advisory_cve(self):
+ pkgs = hawkey.Query(self.sack).filter(advisory_cve="CVE-1967-BEATLES").run()
+ self.assertEqual(pkgs, self.expected_pkgs)
+
+class TestQuerySetOperations(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+ self.q = hawkey.Query(self.sack)
+ self.q1 = self.q.filter(version="4")
+ self.q2 = self.q.filter(name__glob="p*")
+
+ def test_difference(self):
+ qi = self.q1.difference(self.q2)
+ difference = [p for p in self.q1 if p not in self.q2]
+ self.assertEqual(qi.run(), difference)
+
+ def test_intersection(self):
+ qi = self.q1.intersection(self.q2)
+ intersection = self.q.filter(version="4", name__glob="p*")
+ self.assertEqual(qi.run(), intersection.run())
+
+ def test_union(self):
+ qu = self.q1.union(self.q2)
+ union = set(self.q1.run() + self.q2.run())
+ self.assertEqual(set(qu), union)
+
+ def test_zzz_queries_not_modified(self):
+ self.assertEqual(len(self.q1), 5)
+ self.assertEqual(len(self.q2), 5)
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import base
+
+import hawkey
+
+class Reldep(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+
+ def test_basic(self):
+ flying = base.by_name(self.sack, "flying")
+ requires = flying.requires
+ self.assertLength(requires, 1)
+ reldep = requires[0]
+ self.assertEqual(str(reldep), "P-lib >= 3")
+
+ def test_custom_creation(self):
+ reldep_str = "P-lib >= 3"
+ reldep = hawkey.Reldep(self.sack, reldep_str)
+ self.assertEqual(reldep_str, str(reldep))
+ reldep_str = "lane = 4"
+ reldep = hawkey.Reldep(self.sack, reldep_str)
+ self.assertEqual(reldep_str, str(reldep))
+ reldep_str = "(foo if bar)"
+ reldep = hawkey.Reldep(self.sack, reldep_str)
+ self.assertEqual(reldep_str, str(reldep))
+ reldep_str = "font(:lang=en)"
+ reldep = hawkey.Reldep(self.sack, reldep_str)
+ self.assertEqual(reldep_str, str(reldep))
+
+ def test_custom_creation_fail(self):
+ reldep_str = "P-lib >="
+ self.assertRaises(hawkey.ValueException, hawkey.Reldep, self.sack,
+ reldep_str)
+ reldep_str = "(foo i bar)"
+ self.assertRaises(hawkey.ValueException, hawkey.Reldep, self.sack,
+ reldep_str)
+
+ def test_custom_querying(self):
+ reldep = hawkey.Reldep(self.sack, "P-lib = 3-3")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 1)
+ # '==' operator is deprecated and the support will be dropped in future
+ # versions (see bug 1847946)
+ reldep = hawkey.Reldep(self.sack, "P-lib == 3-3")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 1)
+ reldep = hawkey.Reldep(self.sack, "P-lib >= 3")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 1)
+ reldep = hawkey.Reldep(self.sack, "(foo or P-lib)")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 1)
+ reldep = hawkey.Reldep(self.sack, "P-lib < 3-3")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 0)
+ reldep = hawkey.Reldep(self.sack, u"\u0159 >= 3")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 0)
+ reldep = hawkey.Reldep(self.sack, "foo >= 1.0-1.fc20")
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 0)
+
+ def test_query_name_only(self):
+ reldep_str = "P-lib"
+ reldep = hawkey.Reldep(self.sack, reldep_str)
+ self.assertEqual(reldep_str, str(reldep))
+ q = hawkey.Query(self.sack).filter(provides=reldep)
+ self.assertLength(q, 1)
+ self.assertEqual(str(q[0]), "penny-lib-4-1.x86_64")
+
+ def test_not_crash(self):
+ self.assertRaises(ValueError, hawkey.Reldep)
--- /dev/null
+#
+# Copyright (C) 2012-2019 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import hawkey
+import unittest
+
+
+class Package(unittest.TestCase):
+ def test_create(self):
+ r = hawkey.Repo("fog")
+ self.assertIsNotNone(r)
+ self.assertRaises(TypeError, hawkey.Repo);
+ self.assertRaises(TypeError, hawkey.Repo, 3)
+ self.assertRaises(TypeError, hawkey.Repo, rain="pouring")
+
+ def test_cost_assignment(self):
+ r = hawkey.Repo("fog")
+ r.cost = 300
+ self.assertEqual(300, r.cost)
+
+ r2 = hawkey.Repo("blizzard")
+ self.assertEqual(1000, r2.cost)
+ with self.assertRaises(TypeError):
+ r2.cost = '4'
+
+ def test_max_parallel_downloads(self):
+ r = hawkey.Repo("fog")
+ r.max_parallel_downloads = 10
+ self.assertEqual(10, r.max_parallel_downloads)
+
+ def test_max_downloads_per_mirror(self):
+ r = hawkey.Repo("fog")
+ r.max_downloads_per_mirror = 10
+ self.assertEqual(10, r.max_downloads_per_mirror)
+
+ def test_str_assignment(self):
+ r = hawkey.Repo('fog')
+ with self.assertRaises(TypeError):
+ r.repomd_fn = 3
+ r.repomd_fn = 'rain'
+ self.assertEqual(r.repomd_fn, 'rain')
+
--- /dev/null
+#
+# Copyright (C) 2012-2019 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+
+import copy
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+
+from . import base
+import libdnf
+import hawkey
+import hawkey.test
+
+class TestSackTest(base.TestCase):
+ def test_sanity(self):
+ assert(self.repo_dir)
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ self.assertEqual(len(sack), 0)
+
+ def test_load_rpm(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_system_repo()
+ self.assertEqual(len(sack), hawkey.test.EXPECT_SYSTEM_NSOLVABLES)
+
+ def test_load_yum(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_system_repo()
+ sack.load_repo(build_cache=True)
+ self.assertEqual(len(sack), hawkey.test.EXPECT_YUM_NSOLVABLES +
+ hawkey.test.EXPECT_SYSTEM_NSOLVABLES)
+
+ # Loading test using hawkey.Repo
+ def test_load_yum_hawkey_Repo(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ sack.load_system_repo()
+ sack.load_repo_hawkey_Repo(build_cache=True)
+ self.assertEqual(len(sack), hawkey.test.EXPECT_YUM_NSOLVABLES +
+ hawkey.test.EXPECT_SYSTEM_NSOLVABLES)
+
+ def test_cache_dir(self):
+ sack = base.TestSack(repo_dir=self.repo_dir)
+ self.assertTrue(sack.cache_dir.startswith("/tmp/pyhawkey"))
+
+class BasicTest(unittest.TestCase):
+ def setUp(self):
+ self.temp_dir = tempfile.mkdtemp(prefix="libdnf_test_")
+ self.cache_dir = os.path.join(self.temp_dir, "cache")
+
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir)
+
+ def test_creation(self):
+ hawkey.Sack(arch="noarch")
+ hawkey.Sack(arch="x86_64")
+
+ def test_deepcopy(self):
+ sack = hawkey.Sack()
+ self.assertRaises(NotImplementedError, copy.deepcopy, sack)
+
+ def test_creation_dir(self):
+ sack = hawkey.Sack(cachedir=self.cache_dir)
+ self.assertFalse(os.access(sack.cache_dir, os.F_OK))
+ sack = hawkey.Sack(make_cache_dir=True)
+ self.assertTrue(os.access(sack.cache_dir, os.F_OK))
+ self.assertRaises(IOError, hawkey.Sack, "", make_cache_dir=True)
+
+ def test_failed_load(self):
+ sack = hawkey.Sack(cachedir=base.cachedir)
+ self._conf = libdnf.conf.ConfigMain()
+ repo_conf = libdnf.conf.ConfigRepo(self._conf)
+ repo_conf.this.disown() # _repo will be the owner of _config
+ repo = libdnf.repo.Repo("name", repo_conf)
+ self.assertRaises(IOError, sack.load_repo, repo)
+ sack = hawkey.Sack()
+
+ # Loading test using hawkey.Repo
+ def test_failed_load_hawkey_Repo(self):
+ sack = hawkey.Sack(cachedir=base.cachedir)
+ repo = hawkey.Repo("name")
+ self.assertRaises(IOError, sack.load_repo, repo)
+ sack = hawkey.Sack()
+
+ def test_unicoded_cachedir(self):
+ # does not raise UnicodeEncodeError
+ hawkey.Sack(cachedir=u"unicod\xe9")
+
+ def test_evr_cmp(self):
+ sack = hawkey.Sack()
+ self.assertEqual(sack.evr_cmp("3:3.10-4", "3:3.10-4"), 0)
+ self.assertLess(sack.evr_cmp("3.10-4", "3.10-5"), 0)
+ self.assertGreater(sack.evr_cmp("3.11-4", "3.10-5"), 0)
+ self.assertGreater(sack.evr_cmp("1:3.10-4", "3.10-5"), 0)
+
+ def test_all_arch(self):
+ sack = hawkey.Sack(arch="x86_64")
+ # greater than noarch as it has picked up the default architecture
+ self.assertGreater(len(sack.list_arches()), 1)
+ sack2 = hawkey.Sack(all_arch=True)
+ self.assertEqual(len(sack2.list_arches()), 0)
+
+
+class PackageWrappingTest(base.TestCase):
+ class MyPackage(hawkey.Package):
+ def __init__(self, initobject, myval):
+ super(PackageWrappingTest.MyPackage, self).__init__(initobject)
+ self.initobject = initobject
+ self.myval = myval
+
+ def test_wrapping(self):
+ sack = base.TestSack(repo_dir=self.repo_dir,
+ PackageClass=self.MyPackage,
+ package_userdata=42)
+ sack.load_system_repo()
+ pkg = sack.create_package(2)
+ # it is the correct type:
+ self.assertIsInstance(pkg, self.MyPackage)
+ self.assertIsInstance(pkg, hawkey.Package)
+ # it received userdata:
+ self.assertEqual(pkg.myval, 42)
+ # the common attributes are working:
+ self.assertEqual(pkg.name, "baby")
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import hawkey
+import unittest
+
+class Sanity(unittest.TestCase):
+ def test_imports(self):
+ self.assertIn('test', hawkey.__all__)
+ self.assertIn('Goal', hawkey.__all__)
+ self.assertNotIn('_QUERY_KEYNAME_MAP', hawkey.__all__)
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+from . import base
+from hawkey import NEVRA
+from sys import version_info as python_version
+
+import hawkey
+
+INP_FOF="four-of-fish-8:3.6.9-11.fc100.x86_64"
+INP_FOF_NOEPOCH="four-of-fish-3.6.9-11.fc100.x86_64"
+INP_FOF_NEV="four-of-fish-8:3.6.9"
+INP_FOF_NA="four-of-fish-3.6.9.i686"
+
+class SubjectTest(base.TestCase):
+ def test_nevra(self):
+ subj = hawkey.Subject(INP_FOF)
+ result = subj.get_nevra_possibilities(forms=hawkey.FORM_NEVRA)
+ self.assertLength(result, 1)
+ self.assertEqual(result[0], NEVRA(name='four-of-fish', epoch=8,
+ version='3.6.9',
+ release='11.fc100',
+ arch='x86_64'))
+
+ subj = hawkey.Subject(INP_FOF_NOEPOCH)
+ result = subj.get_nevra_possibilities(forms=hawkey.FORM_NEVRA)
+ self.assertEqual(result[0], NEVRA(name='four-of-fish', epoch=None,
+ version='3.6.9',
+ release='11.fc100',
+ arch='x86_64'))
+
+ def test_nevr(self):
+ subj = hawkey.Subject(INP_FOF)
+ expect = NEVRA(name='four-of-fish', epoch=8, version='3.6.9',
+ release='11.fc100.x86_64', arch=None)
+ self.assertEqual(subj.get_nevra_possibilities(forms=hawkey.FORM_NEVR)[0],
+ expect)
+
+ def test_nevr_fail(self):
+ subj = hawkey.Subject("four-of")
+ self.assertLength(subj.get_nevra_possibilities(forms=hawkey.FORM_NEVR),
+ 0)
+
+ def test_nev(self):
+ subj = hawkey.Subject(INP_FOF_NEV)
+ nevra_possibilities = subj.get_nevra_possibilities(forms=hawkey.FORM_NEV)
+ self.assertLength(nevra_possibilities, 1)
+ self.assertEqual(nevra_possibilities[0],
+ NEVRA(name='four-of-fish', epoch=8,
+ version='3.6.9', release=None, arch=None))
+
+ def test_na(self):
+ subj = hawkey.Subject(INP_FOF_NA)
+ nevra_possibilities = subj.get_nevra_possibilities(forms=hawkey.FORM_NA)
+ self.assertLength(nevra_possibilities, 1)
+ self.assertEqual(nevra_possibilities[0],
+ NEVRA(name='four-of-fish-3.6.9', epoch=None,
+ version=None, release=None, arch='i686'))
+
+ def test_custom_list(self):
+ subj = hawkey.Subject(INP_FOF)
+ result = subj.get_nevra_possibilities(forms=[hawkey.FORM_NEVRA,
+ hawkey.FORM_NEVR])
+ self.assertLength(result, 2)
+ self.assertEqual(result[0], NEVRA(name='four-of-fish', epoch=8,
+ version='3.6.9',
+ release='11.fc100',
+ arch='x86_64'))
+ self.assertEqual(result[1], NEVRA(name='four-of-fish', epoch=8, version='3.6.9',
+ release='11.fc100.x86_64', arch=None))
+
+ def test_combined(self):
+ """ Test we get all the possible NEVRA parses. """
+ subj = hawkey.Subject(INP_FOF)
+ # the epoch in INP_FOF nicely limits the nevra_possibilities:
+ expect = (
+ NEVRA(name='four-of-fish', epoch=8, version='3.6.9', release='11.fc100', arch='x86_64'),
+ NEVRA(name='four-of-fish', epoch=8, version='3.6.9', release='11.fc100.x86_64',
+ arch=None)
+ )
+ result = subj.get_nevra_possibilities()
+ self.assertEqual(len(result), len(expect))
+ for idx in range(0, len(expect)):
+ self.assertEqual(expect[idx], result[idx])
+
+ subj = hawkey.Subject(INP_FOF_NOEPOCH)
+ expect = (
+ NEVRA(name='four-of-fish', epoch=None, version='3.6.9',
+ release='11.fc100', arch='x86_64'),
+ NEVRA(name='four-of-fish-3.6.9-11.fc100', epoch=None, version=None,
+ release=None, arch='x86_64'),
+ NEVRA(name='four-of-fish-3.6.9-11.fc100.x86_64', epoch=None, version=None,
+ release=None, arch=None),
+ NEVRA(name='four-of-fish', epoch=None, version='3.6.9',
+ release='11.fc100.x86_64', arch=None),
+ NEVRA(name='four-of-fish-3.6.9', epoch=None, version='11.fc100.x86_64',
+ release=None, arch=None)
+ )
+ result = subj.get_nevra_possibilities()
+ self.assertEqual(len(result), len(expect))
+ for idx in range(0, len(expect)):
+ self.assertEqual(expect[idx], result[idx])
+
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from __future__ import absolute_import
+
+from . import base
+import hawkey
+import unittest
+
+class Util(unittest.TestCase):
+ def test_chksum_name(self):
+ name = hawkey.chksum_name(hawkey.CHKSUM_SHA256)
+ self.assertEqual(name, "sha256")
+
+ def test_chksum_type(self):
+ t = hawkey.chksum_type("SHA1")
+ self.assertEqual(t, hawkey.CHKSUM_SHA1)
+ self.assertRaises(ValueError, hawkey.chksum_type, "maID")
+
+ def test_split_nevra(self):
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "no.go")
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "")
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "eyes-8:-4.fc18.x86_64")
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "eyes-4.fc18.x86_64")
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "eyes--4.fc18.x86_64")
+ self.assertRaises(hawkey.ValueException, hawkey.split_nevra, "eyes-8:1.2.3-4.")
+
+ nevra = hawkey.split_nevra("eyes-8:1.2.3-4.fc18.x86_64")
+ self.assertEqual(nevra.name, "eyes")
+ self.assertEqual(nevra.epoch, 8)
+ self.assertEqual(nevra.version, "1.2.3")
+ self.assertEqual(nevra.release, "4.fc18")
+ self.assertEqual(nevra.arch, "x86_64")
+
+class UtilWithSack(base.TestCase):
+ def setUp(self):
+ self.sack = base.TestSack(repo_dir=self.repo_dir)
+ self.sack.load_system_repo()
+
+ def test_nevra_to_query(self):
+ nevra = hawkey.split_nevra("baby-6:5.0-11.x86_64")
+ q = nevra.to_query(self.sack)
+ self.assertLength(q, 1)
+ pkg = str(q[0])
+ self.assertEqual(pkg, "baby-6:5.0-11.x86_64")
--- /dev/null
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+#
+# Licensed under the GNU Lesser General Public License Version 2.1
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from sys import version_info as python_version
+import unittest
+import hawkey
+
+class Version(unittest.TestCase):
+ def test_version(self):
+ if python_version.major < 3:
+ self.assertIsInstance(hawkey.VERSION, unicode)
+ else:
+ self.assertIsInstance(hawkey.VERSION, str)
+ self.assertGreaterEqual(len(hawkey.VERSION), 5)
+ self.assertEqual(hawkey.VERSION.count('.'), 2)
--- /dev/null
+add_subdirectory(libdnf/conf)
+add_subdirectory(libdnf/module/modulemd)
+add_subdirectory(libdnf/module)
+add_subdirectory(libdnf/repo)
+add_subdirectory(libdnf/transaction)
+add_subdirectory(libdnf/sack)
+add_subdirectory(hawkey)
+add_subdirectory(libdnf)
+
+
+
+pkg_check_modules(CPPUNIT REQUIRED cppunit)
+
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/run_tests.cpp
+)
+
+add_executable(run_tests ${LIBDNF_TEST_SOURCES} ${LIBDNF_TEST_HEADERS})
+target_link_libraries(run_tests libdnf cppunit)
+
+add_test(NAME test_cpp COMMAND ${CMAKE_CURRENT_BINARY_DIR}/run_tests DEPENDS run_tests COMMENT "Running CPPUNIT tests...")
+set_property(TEST test_cpp PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/libdnf")
--- /dev/null
+set(hawkeytest_SRCS
+ fixtures.cpp
+ test_advisory.cpp
+ test_advisorypkg.cpp
+ test_advisoryref.cpp
+ test_goal.cpp
+ test_iutil.cpp
+ test_main.cpp
+ test_package.cpp
+ test_packagelist.cpp
+ test_packageset.cpp
+ test_reldep.cpp
+ test_repo.cpp
+ test_query.cpp
+ test_sack.cpp
+ test_selector.cpp
+ test_subject.cpp
+ test_util.cpp
+ testshared.cpp
+ testsys.cpp
+)
+
+add_library(testshared STATIC testshared.cpp)
+set_target_properties(testshared PROPERTIES COMPILE_FLAGS -fPIC)
+
+add_executable(test_hawkey_main ${hawkeytest_SRCS})
+# The binary links in testshared which was built with -fPIC
+set_target_properties(test_hawkey_main PROPERTIES COMPILE_FLAGS -fPIC)
+target_link_libraries(test_hawkey_main
+ libdnf
+ ${CHECK_LDFLAGS}
+ ${SOLV_LIBRARY}
+ ${SOLVEXT_LIBRARY}
+ ${RPMDB_LIBRARY}
+)
+add_test(test_hawkey_main test_hawkey_main "${CMAKE_CURRENT_SOURCE_DIR}/data/tests/hawkey/")
+set_property(TEST test_hawkey_main PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/libdnf")
--- /dev/null
+
+== The python/ directory ==
+module/ contains the hawkey.test module used for testing Python bindings of hawkey and its Python clients.
+
+tests/ contains the unit tests themselves.
+
+== The repos/ directory ==
+This directory contains sample package data for testing. It is crucial to
+maintain integrity of packages as described by the .repo files, for instance the
+same (equal NEVRA) package present in two different repos needs to keep the same
+provides and requires at both places.
+
+The goal is to have as few packages as possible, ideally one or two per a
+specific testing role they can play:
+
+flying
+* installed at a version older than anything from repositories
+* there's one updated version with different arch than the installed
+* the latest available version is not installable
+
+fool
+* installed version available from main repo, updates repo contains a newer version
+* the updates version obsoletes two packages
+* installonly testing
+
+penny, penny-lib
+* have summaries
+* installed in the highest available version
+* penny-lib is architecture dependent
+* 'penny-lib' provides 'P-lib' that 'flying' needs, so it can not be removed by itself.
+
+walrus
+* not installed, available in the main repo, update available in updates
+* requires two packages
+
+semolina
+* for multilib install testing
+
+pilchard
+* for selector upgrade testing
+
+hello
+* depends on 'goodbye' which is not provided by anything else
+
+jay
+* installed twice, not updatable from main.
+* downgrade available from main.
+
+baby
+* installed at a version newer than anything available (downgrade, distupgrade testing)
+* has epoch (testing evr parsing)
+
+foolish-grin
+* in the "vendor" repo, for testing vendor change
+
+gun
+* installed only in the i686 version
+* higher version of x86_64 arch is available in "vendor" repo (distupgrade doesn't replace it)
+* testing forcebest/arches interaction
+
+pigs, tour
+* testing file reqiures
+* tour is available as a command-line .rpm too
+
+dodo, dodo-dep-a, dodo-dep-b
+* testing favor/disfavor
+
+bloop, bloop-ext
+* bloop-1.0 installed, bloop-ext-1.0 and *-2.0 in updates
+* for testing package locking
+
+=== repos/yum ===
+
+To test loading of yum repos we need an actual yum repo. It currently consists
+of two packages ("mystery", "tour") and generated repodata. The specfiles are
+included, all the package payload is generated in them. To rebuild them, e.g.:
+
+ rpmbuild -bb tour.spec
+
+If things change in these packages the respective changes need to be made in the
+unit tests too for them to pass.
+
+The command to do the metadata rebuild from hawkey/tests/repos/yum:
+
+ createrepo --deltas --oldpackagedirs=../yum_oldrpms/ --no-database .
+
+Or use the 'recreate' script in the directory.
--- /dev/null
+/*
+ * Copyright (C) 2012-2015 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/hy-package.h"
+#include "libdnf/hy-repo.h"
+#include "libdnf/hy-iutil.h"
+#include "libdnf/dnf-sack-private.hpp"
+
+#include "fixtures.h"
+#include "testsys.h"
+
+#include <check.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+/* define the global variable */
+struct TestGlobals_s test_globals;
+
+static DnfSack *
+create_ut_sack(void)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ dnf_sack_set_arch(sack, TEST_FIXED_ARCH, NULL);
+ dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL);
+ test_globals.sack = sack;
+ g_debug("DnfSack for UT created: %p", sack);
+ return sack;
+}
+
+static int
+setup_with(DnfSack *sack, ...)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ va_list names;
+ int ret = 0;
+
+ va_start(names, sack);
+ const char *name = va_arg(names, const char *);
+ while (name) {
+ const char *path = pool_tmpjoin(pool, test_globals.repo_dir,
+ name, ".repo");
+ int installed = !strncmp(name, HY_SYSTEM_REPO_NAME,
+ strlen(HY_SYSTEM_REPO_NAME));
+
+ ret |= load_repo(pool, name, path, installed);
+ name = va_arg(names, const char *);
+ }
+ va_end(names);
+ return ret;
+}
+
+static
+void add_cmdline(DnfSack *sack)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char *path = pool_tmpjoin(pool, test_globals.repo_dir,
+ "yum/tour-4-6.noarch.rpm", NULL);
+ DnfPackage *pkg = dnf_sack_add_cmdline_package(sack, path);
+ g_object_unref(pkg);
+}
+
+void
+fixture_cmdline_only(void)
+{
+ DnfSack *sack = create_ut_sack();
+ add_cmdline(sack);
+}
+
+void
+fixture_empty(void)
+{
+ create_ut_sack();
+}
+
+void
+fixture_greedy_only(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, "greedy", NULL));
+}
+
+void
+fixture_installonly(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, "@System-k", "installonly", NULL));
+}
+
+void
+fixture_system_only(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, NULL));
+}
+
+void
+fixture_verify(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, "@System-broken", NULL));
+}
+
+void
+fixture_with_change(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "change", NULL));
+}
+
+void
+fixture_with_cmdline(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, NULL));
+ add_cmdline(sack);
+}
+
+void
+fixture_with_forcebest(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "forcebest", NULL));
+}
+
+void
+fixture_with_main(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "main", NULL));
+}
+
+void
+fixture_with_updates(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "updates", NULL));
+}
+
+void
+fixture_with_vendor(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "vendor", NULL));
+}
+
+void
+fixture_all(void)
+{
+ DnfSack *sack = create_ut_sack();
+ fail_if(setup_with(sack, HY_SYSTEM_REPO_NAME, "main", "updates", NULL));
+}
+
+void fixture_yum(void)
+{
+ DnfSack *sack = create_ut_sack();
+ setup_yum_sack(sack, YUM_REPO_NAME);
+}
+
+void fixture_reset(void)
+{
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, NULL);
+ dnf_sack_set_installonly_limit(sack, 0);
+ dnf_sack_set_excludes(sack, NULL);
+ dnf_sack_repo_enabled(sack, "main", 1);
+ dnf_sack_repo_enabled(sack, "updates", 1);
+}
+
+void setup_yum_sack(DnfSack *sack, const char *yum_repo_name)
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ const char *repo_path = pool_tmpjoin(pool, test_globals.repo_dir,
+ YUM_DIR_SUFFIX, NULL);
+ fail_if(access(repo_path, X_OK));
+ HyRepo repo = glob_for_repofiles(pool, yum_repo_name, repo_path);
+
+ fail_if(!dnf_sack_load_repo(sack, repo,
+ DNF_SACK_LOAD_FLAG_BUILD_CACHE |
+ DNF_SACK_LOAD_FLAG_USE_FILELISTS |
+ DNF_SACK_LOAD_FLAG_USE_UPDATEINFO |
+ DNF_SACK_LOAD_FLAG_USE_PRESTO, NULL));
+ fail_unless(dnf_sack_count(sack) == TEST_EXPECT_YUM_NSOLVABLES);
+ hy_repo_free(repo);
+}
+
+void
+teardown(void)
+{
+ g_object_unref(test_globals.sack);
+ test_globals.sack = NULL;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FIXTURES_H
+#define FIXTURES_H
+
+
+#include "libdnf/dnf-sack.h"
+
+struct TestGlobals_s {
+ char *repo_dir;
+ DnfSack *sack;
+ char *tmpdir;
+};
+
+/* global data used to pass values from fixtures to tests */
+extern struct TestGlobals_s test_globals;
+
+void fixture_cmdline_only(void);
+void fixture_empty(void);
+void fixture_greedy_only(void);
+void fixture_installonly(void);
+void fixture_system_only(void);
+void fixture_verify(void);
+void fixture_with_change(void);
+void fixture_with_cmdline(void);
+void fixture_with_forcebest(void);
+void fixture_with_main(void);
+void fixture_with_updates(void);
+void fixture_with_vendor(void);
+void fixture_all(void);
+void fixture_yum(void);
+void fixture_reset(void);
+void setup_yum_sack(DnfSack *sack, const char *yum_repo_name);
+void teardown(void);
+
+#endif /* FIXTURES_H */
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+#include "libdnf/dnf-advisory.h"
+#include "libdnf/dnf-advisorypkg.h"
+#include "libdnf/dnf-advisoryref.h"
+#include "libdnf/hy-package.h"
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+static DnfAdvisory *advisory;
+
+static void
+advisory_fixture(void)
+{
+ fixture_yum();
+
+ DnfPackage *pkg;
+ GPtrArray *advisories;
+
+ pkg = by_name(test_globals.sack, "tour");
+ advisories = dnf_package_get_advisories(pkg, HY_GT);
+
+ advisory = static_cast<DnfAdvisory *>(g_steal_pointer(&g_ptr_array_index(advisories, 0)));
+
+ g_ptr_array_unref(advisories);
+ g_object_unref(pkg);
+}
+
+static void
+advisory_teardown(void)
+{
+ dnf_advisory_free(advisory);
+ teardown();
+}
+
+START_TEST(test_title)
+{
+ ck_assert_str_eq(dnf_advisory_get_title(advisory), "lvm2-2.02.39-7.fc10");
+}
+END_TEST
+
+START_TEST(test_id)
+{
+ ck_assert_str_eq(dnf_advisory_get_id(advisory), "FEDORA-2008-9969");
+}
+END_TEST
+
+START_TEST(test_type)
+{
+ ck_assert_int_eq(dnf_advisory_get_kind(advisory), DNF_ADVISORY_KIND_BUGFIX);
+}
+END_TEST
+
+START_TEST(test_description)
+{
+ ck_assert_str_eq(
+ dnf_advisory_get_description(advisory),
+ "An example update to the tour package.");
+}
+END_TEST
+
+START_TEST(test_rights)
+{
+ fail_if(dnf_advisory_get_rights(advisory));
+}
+END_TEST
+
+START_TEST(test_updated)
+{
+ ck_assert_int_eq(dnf_advisory_get_updated(advisory), 1228822286);
+}
+END_TEST
+
+START_TEST(test_packages)
+{
+ GPtrArray *pkglist = dnf_advisory_get_packages(advisory);
+
+ ck_assert_int_eq(pkglist->len, 1);
+ auto package = static_cast<DnfAdvisoryPkg *>(g_ptr_array_index(pkglist, 0));
+ ck_assert_str_eq(
+ dnf_advisorypkg_get_filename(package),
+ "tour.noarch.rpm");
+
+ g_ptr_array_unref(pkglist);
+}
+END_TEST
+
+START_TEST(test_refs)
+{
+ DnfAdvisoryRef *reference;
+ GPtrArray *reflist = dnf_advisory_get_references(advisory);
+
+ ck_assert_int_eq(reflist->len, 2);
+ reference = static_cast<DnfAdvisoryRef *>(g_ptr_array_index(reflist, 0));
+ ck_assert_str_eq(
+ dnf_advisoryref_get_url(reference),
+ "https://bugzilla.redhat.com/show_bug.cgi?id=472090");
+ reference = static_cast<DnfAdvisoryRef *>(g_ptr_array_index(reflist, 1));
+ ck_assert_str_eq(
+ dnf_advisoryref_get_url(reference),
+ "https://bugzilla.gnome.com/show_bug.cgi?id=472091");
+
+ g_ptr_array_unref(reflist);
+}
+END_TEST
+
+Suite *
+advisory_suite(void)
+{
+ Suite *s = suite_create("Advisory");
+ TCase *tc;
+
+ tc = tcase_create("WithRealRepo");
+ tcase_add_unchecked_fixture(tc, advisory_fixture, advisory_teardown);
+ tcase_add_test(tc, test_title);
+ tcase_add_test(tc, test_id);
+ tcase_add_test(tc, test_type);
+ tcase_add_test(tc, test_description);
+ tcase_add_test(tc, test_rights);
+ tcase_add_test(tc, test_updated);
+ tcase_add_test(tc, test_packages);
+ tcase_add_test(tc, test_refs);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+#include "libdnf/dnf-advisory.h"
+#include "libdnf/dnf-advisorypkg.h"
+#include "libdnf/hy-package.h"
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+static DnfAdvisoryPkg *advisorypkg;
+
+static void
+advisorypkg_fixture(void)
+{
+ fixture_yum();
+
+ DnfPackage *pkg;
+ GPtrArray *advisories;
+ DnfAdvisory *advisory;
+ GPtrArray *pkglist;
+
+ pkg = by_name(test_globals.sack, "tour");
+ advisories = dnf_package_get_advisories(pkg, HY_GT);
+ advisory = static_cast<DnfAdvisory *>(g_ptr_array_index(advisories, 0));
+ pkglist = dnf_advisory_get_packages(advisory);
+ advisorypkg = static_cast<DnfAdvisoryPkg *>(g_steal_pointer(&g_ptr_array_index(pkglist, 0)));
+
+ g_ptr_array_unref(pkglist);
+ g_ptr_array_unref(advisories);
+ g_object_unref(pkg);
+}
+
+static void
+advisorypkg_teardown(void)
+{
+ dnf_advisorypkg_free(advisorypkg);
+ teardown();
+}
+
+START_TEST(test_name)
+{
+ ck_assert_str_eq(dnf_advisorypkg_get_name(advisorypkg), "tour");
+}
+END_TEST
+
+START_TEST(test_evr)
+{
+ ck_assert_str_eq(dnf_advisorypkg_get_evr(advisorypkg), "4-7");
+}
+END_TEST
+
+START_TEST(test_arch)
+{
+ ck_assert_str_eq(dnf_advisorypkg_get_arch(advisorypkg), "noarch");
+}
+END_TEST
+
+START_TEST(test_filename)
+{
+ ck_assert_str_eq(dnf_advisorypkg_get_filename(advisorypkg), "tour.noarch.rpm");
+}
+END_TEST
+
+Suite *
+advisorypkg_suite(void)
+{
+ Suite *s = suite_create("AdvisoryPkg");
+ TCase *tc;
+
+ tc = tcase_create("WithRealRepo");
+ tcase_add_unchecked_fixture(tc, advisorypkg_fixture, advisorypkg_teardown);
+ tcase_add_test(tc, test_name);
+ tcase_add_test(tc, test_evr);
+ tcase_add_test(tc, test_arch);
+ tcase_add_test(tc, test_filename);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+#include "libdnf/dnf-advisory.h"
+#include "libdnf/dnf-advisoryref.h"
+#include "libdnf/hy-package.h"
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+static DnfAdvisoryRef *reference;
+
+static void
+advisoryref_fixture(void)
+{
+ fixture_yum();
+
+ DnfPackage *pkg;
+ GPtrArray *advisories;
+ GPtrArray *reflist;
+
+ pkg = by_name(test_globals.sack, "tour");
+ advisories = dnf_package_get_advisories(pkg, HY_GT);
+ auto advisory = static_cast<DnfAdvisory *>(g_ptr_array_index(advisories, 0));
+ reflist = dnf_advisory_get_references(advisory);
+ reference = static_cast<DnfAdvisoryRef *>(g_steal_pointer(&g_ptr_array_index(reflist, 0)));
+
+ g_ptr_array_unref(reflist);
+ g_ptr_array_unref(advisories);
+ g_object_unref(pkg);
+}
+
+static void
+advisoryref_teardown(void)
+{
+ dnf_advisoryref_free(reference);
+ teardown();
+}
+
+START_TEST(test_type)
+{
+ ck_assert_int_eq(dnf_advisoryref_get_kind(reference), DNF_REFERENCE_KIND_BUGZILLA);
+}
+END_TEST
+
+START_TEST(test_id)
+{
+ ck_assert_str_eq(dnf_advisoryref_get_id(reference), "472090");
+}
+END_TEST
+
+START_TEST(test_title)
+{
+ ck_assert_str_eq(dnf_advisoryref_get_title(reference), "/etc/init.d/clvmd points to /usr/sbin for LVM tools");
+}
+END_TEST
+
+START_TEST(test_url)
+{
+ ck_assert_str_eq(dnf_advisoryref_get_url(reference), "https://bugzilla.redhat.com/show_bug.cgi?id=472090");
+}
+END_TEST
+
+Suite *
+advisoryref_suite(void)
+{
+ Suite *s = suite_create("AdvisoryRef");
+ TCase *tc;
+
+ tc = tcase_create("WithRealRepo");
+ tcase_add_unchecked_fixture(tc, advisoryref_fixture, advisoryref_teardown);
+ tcase_add_test(tc, test_type);
+ tcase_add_test(tc, test_id);
+ tcase_add_test(tc, test_title);
+ tcase_add_test(tc, test_url);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/goal/Goal.hpp"
+#include "libdnf/dnf-types.h"
+#include "libdnf/hy-goal-private.hpp"
+#include "libdnf/hy-iutil.h"
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-packageset.h"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-repo.h"
+#include "libdnf/hy-query.h"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/dnf-goal.h"
+#include "libdnf/hy-selector.h"
+#include "libdnf/hy-util-private.hpp"
+#include "libdnf/sack/packageset.hpp"
+
+#include "fixtures.h"
+#include "testsys.h"
+#include "test_suites.h"
+
+#include <check.h>
+#include <glib.h>
+#include <stdarg.h>
+#include <vector>
+
+static DnfPackage *
+get_latest_pkg(DnfSack *sack, const char *name)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, name);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_NEQ, HY_SYSTEM_REPO_NAME);
+ hy_query_filter_latest_per_arch(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1,
+ "get_latest_pkg() failed finding '%s'.", name);
+ auto pkg = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist, 0)));
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+ return pkg;
+}
+
+static DnfPackage *
+get_available_pkg(DnfSack *sack, const char *name)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, name);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_NEQ, HY_SYSTEM_REPO_NAME);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1);
+ auto pkg = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist, 0)));
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+ return pkg;
+}
+
+/* make Sack think we are unable to determine the running kernel */
+static Id
+mock_running_kernel_no(DnfSack *sack)
+{
+ return -1;
+}
+
+/* make Sack think k-1-1 is the running kernel */
+static Id
+mock_running_kernel(DnfSack *sack)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "k");
+ hy_query_filter(q, HY_PKG_EVR, HY_EQ, "1-1");
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1);
+ auto pkg = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist, 0)));
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+ Id id = dnf_package_get_id(pkg);
+ g_object_unref(pkg);
+ return id;
+}
+
+static int
+size_and_free(GPtrArray *plist)
+{
+ int c = plist->len;
+ g_ptr_array_unref(plist);
+ return c;
+}
+
+static void
+userinstalled(DnfSack *sack, HyGoal goal, const char *name)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, name);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
+ GPtrArray *plist = hy_query_run(q);
+
+ for(guint i = 0; i < plist->len; i++) {
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index (plist, i));
+ hy_goal_userinstalled(goal, pkg);
+ }
+
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+
+/* assert on installed-upgraded-erased-obsoleted numbers */
+static void
+assert_iueo(HyGoal goal, int i, int u, int e, int o)
+{
+ ck_assert_int_eq(size_and_free(hy_goal_list_installs(goal, NULL)), i);
+ ck_assert_int_eq(size_and_free(hy_goal_list_upgrades(goal, NULL)), u);
+ ck_assert_int_eq(size_and_free(hy_goal_list_erasures(goal, NULL)), e);
+ ck_assert_int_eq(size_and_free(hy_goal_list_obsoleted(goal, NULL)), o);
+}
+
+START_TEST(test_goal_sanity)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(goal == NULL);
+ fail_unless(dnf_sack_count(test_globals.sack) ==
+ TEST_EXPECT_SYSTEM_NSOLVABLES +
+ TEST_EXPECT_MAIN_NSOLVABLES +
+ TEST_EXPECT_UPDATES_NSOLVABLES);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_actions)
+{
+ DnfPackage *pkg = get_latest_pkg(test_globals.sack, "walrus");
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(hy_goal_has_actions(goal, DNF_INSTALL));
+ fail_if(hy_goal_install(goal, pkg));
+ fail_unless(hy_goal_has_actions(goal, DNF_INSTALL));
+ g_object_unref(pkg);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_list_err)
+{
+ g_autoptr(GError) error = NULL;
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_unless(hy_goal_list_installs(goal, &error) == NULL);
+ fail_unless(error->code == DNF_ERROR_INTERNAL_ERROR);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install)
+{
+ DnfPackage *pkg = get_latest_pkg(test_globals.sack, "walrus");
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(hy_goal_install(goal, pkg));
+ g_object_unref(pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 2, 0, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_multilib)
+{
+ // Tests installation of multilib package. The package is selected via
+ // install query, allowing the depsolver maximum influence on the selection.
+
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "semolina");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 0, 0, 0);
+ hy_selector_free(sltr);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_selector)
+{
+ HySelector sltr;
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ // test arch forcing
+ sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "semolina");
+ hy_selector_set(sltr, HY_PKG_ARCH, HY_EQ, "i686");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 0, 0, 0);
+
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ const char *nvra = dnf_package_get_nevra(
+ static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)));
+ ck_assert_str_eq(nvra, "semolina-2-0.i686");
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_selector_err)
+{
+ // Test that using the hy_goal_*_selector() methods returns an error for
+ // selectors invalid in this context.
+
+ int rc;
+ g_autoptr(GError) error = NULL;
+
+ HySelector sltr;
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_ARCH, HY_EQ, "i586");
+ fail_unless(!hy_goal_install_selector(goal, sltr, &error));
+ fail_unless(error->code == DNF_ERROR_BAD_SELECTOR);
+ hy_selector_free(sltr);
+
+ g_clear_error(&error);
+ sltr = hy_selector_create(test_globals.sack);
+ rc = hy_selector_set(sltr, HY_PKG_NAME, HY_GT, "semolina");
+ fail_unless(rc == DNF_ERROR_BAD_SELECTOR);
+ hy_selector_free(sltr);
+
+ sltr = hy_selector_create(test_globals.sack);
+ fail_unless(hy_selector_set(sltr, HY_PKG, HY_EQ, HY_SYSTEM_REPO_NAME));
+ hy_selector_free(sltr);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_selector_two)
+{
+ // check that we can add and resolve two selector installs to the Goal
+ HySelector sltr;
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "semolina");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ hy_selector_free(sltr);
+
+ sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "fool");
+ fail_if(hy_goal_upgrade_selector(goal, sltr));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 1, 0, 1);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_selector_nomatch)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "crabalocker");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_weak_deps)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "B");
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ HyGoal goal2 = hy_goal_clone(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ // recommended package C is installed too
+ assert_iueo(goal, 2, 0, 0, 0);
+
+ fail_if(hy_goal_run_flags(goal2, DNF_IGNORE_WEAK_DEPS));
+ assert_iueo(goal2, 1, 0, 0, 0);
+ hy_goal_free(goal);
+ hy_goal_free(goal2);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_goal_selector_glob)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_GLOB, "*emolin*"));
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 0, 0, 0);
+
+ hy_goal_free(goal);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_goal_selector_provides_glob)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_PROVIDES, HY_GLOB, "P*"));
+ fail_if(hy_goal_erase_selector_flags(goal, sltr, 0));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 1, 0);
+
+ hy_goal_free(goal);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+
+START_TEST(test_goal_selector_upgrade_provides)
+{
+ DnfSack *sack = test_globals.sack;
+ HySelector sltr = hy_selector_create(sack);
+ HyGoal goal = hy_goal_create(sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_PROVIDES, HY_EQ, "fool"));
+ fail_if(hy_goal_upgrade_selector(goal, sltr));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 1, 0, 1);
+ hy_goal_free(goal);
+
+ sltr = hy_selector_create(sack);
+ goal = hy_goal_create(sack);
+ fail_if(hy_selector_set(sltr, HY_PKG_PROVIDES, HY_EQ, "fool > 1-3"));
+ fail_if(hy_goal_upgrade_selector(goal, sltr));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 1, 0, 1);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_selector_file)
+{
+ DnfSack *sack = test_globals.sack;
+ HySelector sltr = hy_selector_create(sack);
+ HyGoal goal = hy_goal_create(sack);
+ fail_if(hy_selector_set(sltr, HY_PKG_FILE, HY_EQ|HY_GLOB, "/*/answers"));
+ fail_if(hy_goal_erase_selector_flags(goal, sltr, 0));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 1, 0);
+ GPtrArray *plist = hy_goal_list_erasures(goal, NULL);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq("fool", dnf_package_get_name(pkg));
+ hy_selector_free(sltr);
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_install_optional)
+{
+ HySelector sltr;
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ // test optional selector installation
+ sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "hello");
+ fail_if(!hy_goal_install_selector_optional(goal, sltr, NULL));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ hy_selector_free(sltr);
+ assert_iueo(goal, 0, 0, 0, 0);
+
+ // test optional package installation
+ DnfPackage *pkg = get_latest_pkg(test_globals.sack, "hello");
+ fail_if(hy_goal_install_optional(goal, pkg));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 0, 0);
+ g_object_unref(pkg);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_upgrade)
+{
+ DnfPackage *pkg = get_latest_pkg(test_globals.sack, "fool");
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(hy_goal_upgrade_to(goal, pkg));
+ g_object_unref(pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 1, 0, 1);
+ hy_goal_free(goal);
+}
+END_TEST
+
+template<const char * (*getCharFromPackage)(DnfPackage*)>
+static void
+assert_list_names(bool wanted, GPtrArray *plist, ...)
+{
+ va_list names;
+ char *name;
+ int count = plist->len;
+ int i = 0;
+ std::vector<const char*> stringVector;
+ stringVector.reserve(count);
+
+ for (int j = 0; j < count; ++j) {
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, j));
+ auto string = getCharFromPackage(pkg);
+ stringVector.push_back(string);
+ }
+
+ va_start(names, plist);
+ while ((name = va_arg(names, char *)) != NULL) {
+ if (i++ >= count) {
+ fail("assert_list_names(): list too short");
+ }
+ bool found = false;
+ for (auto string: stringVector) {
+ if (strcmp(string, name) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if ((wanted && !found) || (!wanted && found)) {
+ fail_unless(false, "assert_list_names(): element '%s' %sfound '%zu'",
+ name, wanted ? "not ": "", stringVector.size());
+ }
+ }
+ // In the wanted case; we expect all the pkgs in the lists to fully
+ // describe each other. Otherwise, in the !wanted case we just care that
+ // all the passed pkg arguments are *not* found in the list, which is
+ // already checked above.
+ if (wanted) {
+ fail_unless(i == count, "assert_list_names(): too many items in the list (%d vs %d)", i, count);
+ }
+ va_end(names);
+}
+
+START_TEST(test_goal_upgrade_all)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ auto pool = dnf_sack_get_pool(test_globals.sack);
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ GPtrArray *plist = hy_goal_list_erasures(goal, NULL);
+ fail_unless(size_and_free(plist) == 0);
+
+ plist = hy_goal_list_obsoleted(goal, NULL);
+ assert_list_names<&dnf_package_get_name>(true, plist, "penny", NULL);
+ g_ptr_array_unref(plist);
+
+ plist = hy_goal_list_upgrades(goal, NULL);
+ int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
+ if (implicitobsoleteusescolors) {
+ // Fedora, Mageia
+ assert_list_names<&dnf_package_get_name>(
+ true, plist, "bloop", "dog", "flying", "fool", "pilchard", "pilchard", NULL);
+ } else {
+ // openSUSE
+ assert_list_names<&dnf_package_get_name>(
+ true, plist, "bloop", "dog", "flying", "fool", NULL);
+ }
+
+ // see all obsoletes of fool:
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ GPtrArray *plist_obs = hy_goal_list_obsoleted_by_package(goal, pkg);
+ assert_list_names<&dnf_package_get_name>(true, plist_obs, "fool", "penny", NULL);
+ g_ptr_array_unref(plist_obs);
+ g_ptr_array_unref(plist);
+
+ fail_unless(size_and_free(hy_goal_list_installs(goal, NULL)) == 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_downgrade)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *to_be_pkg = get_available_pkg(sack, "baby");
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_install(goal, to_be_pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 0, 0);
+
+ GPtrArray *plist = hy_goal_list_downgrades(goal, NULL);
+ fail_unless(plist->len == 1);
+
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_evr(pkg),
+ "6:4.9-3");
+ GPtrArray *obsoleted = hy_goal_list_obsoleted_by_package(goal, pkg);
+ fail_unless(obsoleted->len == 1);
+ auto old_pkg = static_cast<DnfPackage *>(g_ptr_array_index(obsoleted, 0));
+ ck_assert_str_eq(dnf_package_get_evr(old_pkg),
+ "6:5.0-11");
+ g_ptr_array_unref(obsoleted);
+ g_ptr_array_unref(plist);
+
+ hy_goal_free(goal);
+ g_object_unref(to_be_pkg);
+}
+END_TEST
+
+START_TEST(test_goal_get_reason)
+{
+ DnfPackage *pkg = get_latest_pkg(test_globals.sack, "walrus");
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ hy_goal_install(goal, pkg);
+ g_object_unref(pkg);
+ hy_goal_run_flags(goal, DNF_NONE);
+
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ guint i;
+ int set = 0;
+ for(i = 0; i < plist->len; i++) {
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index (plist, i));
+ if (!strcmp(dnf_package_get_name(pkg), "walrus")) {
+ set |= 1 << 0;
+ fail_unless(hy_goal_get_reason(goal, pkg) == HY_REASON_USER);
+ }
+ if (!strcmp(dnf_package_get_name(pkg), "semolina")) {
+ set |= 1 << 1;
+ fail_unless(hy_goal_get_reason(goal, pkg) == HY_REASON_DEP);
+ }
+ }
+ fail_unless(set == 3);
+
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_get_reason_selector)
+{
+
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ HyGoal goal = hy_goal_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "walrus"));
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ hy_selector_free(sltr);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ fail_unless(plist->len == 2);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ fail_unless(hy_goal_get_reason(goal, pkg) == HY_REASON_USER);
+
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_describe_problem_rules)
+{
+ g_autoptr(GError) error = NULL;
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = get_latest_pkg(sack, "hello");
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_install(goal, pkg);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE));
+ fail_unless(hy_goal_list_installs(goal, &error) == NULL);
+ fail_unless(error->code == DNF_ERROR_NO_SOLUTION);
+ fail_unless(hy_goal_count_problems(goal) > 0);
+
+ auto problems = goal->describeProblemRules(0, true);
+ const char *expected[] = {
+ "conflicting requests",
+ "nothing provides goodbye needed by hello-1-1.noarch from main"
+ };
+ ck_assert_int_eq(problems.size(), 2);
+ ck_assert_str_eq(problems[0].c_str(), expected[0]);
+ ck_assert_str_eq(problems[1].c_str(), expected[1]);
+
+ g_object_unref(pkg);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_no_reinstall)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = get_latest_pkg(sack, "penny");
+ HyGoal goal = hy_goal_create(sack);
+ fail_if(hy_goal_install(goal, pkg));
+ g_object_unref(pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_erase_simple)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name_repo(sack, "penny", HY_SYSTEM_REPO_NAME);
+ HyGoal goal = hy_goal_create(sack);
+ fail_if(hy_goal_erase(goal, pkg));
+ g_object_unref(pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 0, 1, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_erase_with_deps)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name_repo(sack, "penny-lib", HY_SYSTEM_REPO_NAME);
+
+ // by default can not remove penny-lib, flying depends on it:
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_erase(goal, pkg);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE));
+ hy_goal_free(goal);
+
+ goal = hy_goal_create(sack);
+ hy_goal_erase(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_ALLOW_UNINSTALL));
+ assert_iueo(goal, 0, 0, 2, 0);
+ hy_goal_free(goal);
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_goal_protected)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackageSet *protected_pkgs = dnf_packageset_new(sack);
+ DnfPackage *pkg = by_name_repo(sack, "penny-lib", HY_SYSTEM_REPO_NAME);
+ DnfPackage *pp = by_name_repo(sack, "flying", HY_SYSTEM_REPO_NAME);
+ const char *expected;
+
+ // when protected_packages set is empty it should remove both packages
+ HyGoal goal = hy_goal_create(sack);
+ DnfPackageSet *empty = dnf_packageset_new(sack);
+ dnf_goal_set_protected(goal, empty);
+ dnf_packageset_free(empty);
+ hy_goal_erase(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_ALLOW_UNINSTALL));
+ assert_iueo(goal, 0, 0, 2, 0);
+ hy_goal_free(goal);
+
+ // fails to uninstall penny-lib because flying is protected
+ goal = hy_goal_create(sack);
+ dnf_packageset_add(protected_pkgs, pp);
+ dnf_goal_set_protected(goal, protected_pkgs);
+ hy_goal_erase(goal, pkg);
+ fail_unless(hy_goal_run_flags(goal, DNF_ALLOW_UNINSTALL));
+ hy_goal_free(goal);
+
+ // removal of protected package explicitly should trigger error
+ goal = hy_goal_create(sack);
+ dnf_goal_set_protected(goal, protected_pkgs);
+ hy_goal_erase(goal, pp);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE));
+ fail_unless(hy_goal_count_problems(goal) == 1);
+ auto problem = goal->describeProblemRules(0, true);
+ expected = "The operation would result in removing "
+ "the following protected packages: flying";
+ fail_if(g_strcmp0(problem[0].c_str(), expected));
+ hy_goal_free(goal);
+
+ dnf_packageset_free(protected_pkgs);
+ g_object_unref(pkg);
+ g_object_unref(pp);
+}
+END_TEST
+
+START_TEST(test_goal_erase_clean_deps)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name_repo(sack, "flying", HY_SYSTEM_REPO_NAME);
+
+ // by default, leave dependencies alone:
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_erase(goal, pkg);
+ hy_goal_run_flags(goal, DNF_NONE);
+ assert_iueo(goal, 0, 0, 1, 0);
+ hy_goal_free(goal);
+
+ // allow deleting dependencies:
+ goal = hy_goal_create(sack);
+ hy_goal_erase_flags(goal, pkg, HY_CLEAN_DEPS);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE) == 0);
+ assert_iueo(goal, 0, 0, 2, 0);
+ hy_goal_free(goal);
+
+ // test userinstalled specification:
+ DnfPackage *penny_pkg = by_name_repo(sack, "penny-lib", HY_SYSTEM_REPO_NAME);
+ goal = hy_goal_create(sack);
+ hy_goal_erase_flags(goal, pkg, HY_CLEAN_DEPS);
+ hy_goal_userinstalled(goal, penny_pkg);
+ // having the same solvable twice in a goal shouldn't break anything:
+ hy_goal_userinstalled(goal, pkg);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE) == 0);
+ assert_iueo(goal, 0, 0, 1, 0);
+ hy_goal_free(goal);
+ g_object_unref(penny_pkg);
+
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_goal_forcebest)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "flying");
+ hy_goal_upgrade_selector(goal, sltr);
+ fail_unless(hy_goal_run_flags(goal, DNF_FORCE_BEST));
+ fail_unless(hy_goal_count_problems(goal) == 1);
+
+ hy_selector_free(sltr);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_favor)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "dodo");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ DnfPackage *pkg = get_latest_pkg(sack, "dodo-dep-a");
+ hy_goal_favor(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ assert_list_names<&dnf_package_get_name>(true, plist, "dodo", "dodo-dep-a", NULL);
+ assert_list_names<&dnf_package_get_name>(false, plist, "dodo-dep-b", NULL);
+ g_ptr_array_unref(plist);
+
+ g_object_unref(pkg);
+ hy_selector_free(sltr);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_disfavor)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "dodo");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ DnfPackage *pkg = get_latest_pkg(sack, "dodo-dep-a");
+ hy_goal_disfavor(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ assert_list_names<&dnf_package_get_name>(true, plist, "dodo", "dodo-dep-b", NULL);
+ assert_list_names<&dnf_package_get_name>(false, plist, "dodo-dep-a", NULL);
+ g_ptr_array_unref(plist);
+
+ g_object_unref(pkg);
+ hy_selector_free(sltr);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_lock)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+
+ // check that installing "bloop-ext" without locking the base works fine
+ // (and auto-updates the base)
+ g_auto(HySubject) subject = hy_subject_create("bloop-ext");
+ g_auto(HySelector) selector = hy_subject_get_best_selector(subject, sack, NULL, FALSE, "updates");
+ fail_if(!hy_goal_install_selector(goal, selector, NULL));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 1, 1, 0, 0);
+
+ GPtrArray *plist = hy_goal_list_installs(goal, NULL);
+ const char *nvra = dnf_package_get_nevra(
+ static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)));
+ ck_assert_str_eq(nvra, "bloop-ext-2.0-1.noarch");
+ g_ptr_array_unref(plist);
+
+ plist = hy_goal_list_upgrades(goal, NULL);
+ nvra = dnf_package_get_nevra(
+ static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)));
+ ck_assert_str_eq(nvra, "bloop-2.0-1.noarch");
+ g_ptr_array_unref(plist);
+
+ hy_goal_free(goal);
+
+ // now redo the same test, but lock the base pkg
+ goal = hy_goal_create(sack);
+
+ g_autoptr(DnfPackage) base_pkg = by_name_repo(sack, "bloop", HY_SYSTEM_REPO_NAME);
+ fail_if(base_pkg == NULL);
+ fail_if(hy_goal_lock(goal, base_pkg, NULL));
+
+ fail_if(!hy_goal_install_selector(goal, selector, NULL));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 1, 0, 0, 0);
+
+ plist = hy_goal_list_installs(goal, NULL);
+ nvra = dnf_package_get_nevra(
+ static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)));
+ ck_assert_str_eq(nvra, "bloop-ext-1.0-1.noarch");
+ g_ptr_array_unref(plist);
+
+ hy_goal_free(goal);
+
+ // now purposely exclude the compatible version and check that we get a
+ // sensical error
+ goal = hy_goal_create(sack);
+ fail_if(hy_goal_lock(goal, base_pkg, NULL));
+
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NEVRA, HY_EQ, "bloop-ext-1.0-1.noarch");
+ hy_query_filter(q, HY_PKG_REPONAME, HY_EQ, "updates");
+ g_autoptr(DnfPackageSet) pset = hy_query_run_set(q);
+ dnf_sack_add_excludes(sack, pset);
+ hy_query_free(q);
+
+ fail_if(!hy_goal_install_selector(goal, selector, NULL));
+ // notice the ! here; we expect failure
+ fail_if(!hy_goal_run_flags(goal, DNF_NONE));
+
+ g_autoptr(GError) error = NULL;
+ fail_unless(hy_goal_list_installs(goal, &error) == NULL);
+ fail_unless(error->code == DNF_ERROR_NO_SOLUTION);
+ fail_unless(hy_goal_count_problems(goal) > 0);
+
+ auto problems = goal->describeProblemRules(0, true);
+ const char *expected[] = {
+ "package bloop-ext-2.0-1.noarch from updates requires bloop = 2.0-1, but none of the providers can be installed",
+ "cannot install both bloop-2.0-1.noarch from updates and bloop-1.0-1.noarch from @System",
+ "conflicting requests",
+ "package bloop-ext-1.0-1.noarch from updates is filtered out by exclude filtering"
+ };
+ ck_assert_int_eq(problems.size(), 4);
+ ck_assert_str_eq(problems[0].c_str(), expected[0]);
+ ck_assert_str_eq(problems[1].c_str(), expected[1]);
+ ck_assert_str_eq(problems[2].c_str(), expected[2]);
+ ck_assert_str_eq(problems[3].c_str(), expected[3]);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_installonly)
+{
+ const char *installonly[] = {"fool", NULL};
+
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 2);
+ DnfPackage *pkg = get_latest_pkg(sack, "fool");
+ HyGoal goal = hy_goal_create(sack);
+ fail_if(hy_goal_upgrade_to(goal, pkg));
+ g_object_unref(pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 0, 1, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_installonly_upgrade_all)
+{
+ const char *installonly[] = {"fool", NULL};
+ DnfSack *sack = test_globals.sack;
+ auto pool = dnf_sack_get_pool(test_globals.sack);
+ HyGoal goal = hy_goal_create(sack);
+
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 2);
+
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ GPtrArray *plist = hy_goal_list_erasures(goal, NULL);
+ assert_list_names<&dnf_package_get_name>(true, plist, "penny", NULL);
+ g_ptr_array_unref(plist);
+ plist = hy_goal_list_installs(goal, NULL);
+ assert_list_names<&dnf_package_get_name>(true, plist, "fool", NULL);
+ g_ptr_array_unref(plist);
+
+ int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
+ if (implicitobsoleteusescolors) {
+ // Fedora, Mageia
+ assert_iueo(goal, 1, 5, 1, 0);
+ } else {
+ // openSUSE
+ assert_iueo(goal, 1, 3, 1, 0);
+ }
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_upgrade_all_excludes)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q = hy_query_create_flags(sack, HY_IGNORE_EXCLUDES);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "pilchard");
+
+ DnfPackageSet *pset = hy_query_run_set(q);
+ dnf_sack_add_excludes(sack, pset);
+ dnf_packageset_free(pset);
+ hy_query_free(q);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ hy_goal_run_flags(goal, DNF_NONE);
+ fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 4);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_upgrade_disabled_repo)
+{
+ DnfSack *sack = test_globals.sack;
+ auto pool = dnf_sack_get_pool(test_globals.sack);
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_upgrade_all(goal);
+ hy_goal_run_flags(goal, DNF_NONE);
+ int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
+ if (implicitobsoleteusescolors) {
+ // Fedora, Mageia
+ fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 6);
+ } else {
+ // openSUSE
+ fail_unless(size_and_free(hy_goal_list_upgrades(goal, NULL)) == 4);
+ }
+ hy_goal_free(goal);
+
+ dnf_sack_repo_enabled(sack, "updates", 0);
+ goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ hy_goal_run_flags(goal, DNF_NONE);
+ assert_iueo(goal, 0, 1, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_describe_problem_excludes)
+{
+ DnfSack *sack = test_globals.sack;
+
+ HyQuery q = hy_query_create_flags(sack, HY_IGNORE_EXCLUDES);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "semolina");
+ DnfPackageSet *pset = hy_query_run_set(q);
+ dnf_sack_add_excludes(sack, pset);
+ dnf_packageset_free(pset);
+ hy_query_free(q);
+
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "semolina");
+ fail_if(!hy_goal_install_selector(goal, sltr, NULL));
+ hy_selector_free(sltr);
+
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE));
+ fail_unless(hy_goal_count_problems(goal) > 0);
+
+ auto problems = goal->describeProblemRules(0, true);
+ const char *expected[] = {
+ "conflicting requests",
+ "package semolina does not exist"
+ };
+ fail_unless(problems.size() >= 2);
+ fail_unless(problems[0] == expected[0]);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_all)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(hy_goal_distupgrade_all(goal));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 0, 1, 0, 0);
+ GPtrArray *plist = hy_goal_list_upgrades(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "flying-3-0.noarch");
+ g_ptr_array_unref(plist);
+
+ plist = hy_goal_list_downgrades(goal, NULL);
+ fail_unless(plist->len == 1);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "baby-6:4.9-3.x86_64");
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_all_excludes)
+{
+ HyQuery q = hy_query_create_flags(test_globals.sack, HY_IGNORE_EXCLUDES);
+ hy_query_filter_provides(q, HY_GT|HY_EQ, "flying", "0");
+ DnfPackageSet *pset = hy_query_run_set(q);
+ dnf_sack_add_excludes(test_globals.sack, pset);
+ dnf_packageset_free(pset);
+ hy_query_free(q);
+
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ fail_if(hy_goal_distupgrade_all(goal));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 0, 0, 0, 0);
+
+ GPtrArray *plist = hy_goal_list_downgrades(goal, NULL);
+ fail_unless(plist->len == 1);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "baby-6:4.9-3.x86_64");
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_all_keep_arch)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ auto pool = dnf_sack_get_pool(test_globals.sack);
+ fail_if(hy_goal_distupgrade_all(goal));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ GPtrArray *plist = hy_goal_list_upgrades(goal, NULL);
+
+ int implicitobsoleteusescolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
+ // gun pkg is not upgraded to latest version of different arch
+ if (implicitobsoleteusescolors) {
+ // Fedora, Mageia
+ assert_iueo(goal, 0, 6, 0, 1);
+ assert_list_names<&dnf_package_get_nevra>(true, plist, "bloop-2.0-1.noarch", "dog-1-2.x86_64", "fool-1-5.noarch",
+ "flying-3.1-0.x86_64", "pilchard-1.2.4-1.x86_64", "pilchard-1.2.4-1.i686", NULL);
+ } else {
+ // openSUSE
+ assert_iueo(goal, 0, 5, 0, 1);
+ assert_list_names<&dnf_package_get_nevra>(true, plist, "bloop-2.0-1.noarch", "dog-1-2.x86_64", "fool-1-5.noarch",
+ "flying-3.1-0.x86_64", "pilchard-1.2.4-2.x86_64", NULL);
+ }
+ g_ptr_array_unref(plist);
+
+ plist = hy_goal_list_obsoleted(goal, NULL);
+ assert_list_names<&dnf_package_get_nevra>(true, plist, "penny-4-1.noarch", NULL);
+ g_ptr_array_unref(plist);
+
+ plist = hy_goal_list_downgrades(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "baby-6:4.9-3.x86_64");
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_selector_upgrade)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "flying");
+ fail_if(hy_goal_distupgrade_selector(goal, sltr));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 0, 1, 0, 0);
+ GPtrArray *plist = hy_goal_list_upgrades(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "flying-3-0.noarch");
+
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_selector_downgrade)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "baby");
+ fail_if(hy_goal_distupgrade_selector(goal, sltr));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 0, 0, 0, 0);
+ GPtrArray *plist = hy_goal_list_downgrades(goal, NULL);
+ fail_unless(plist->len == 1);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(plist, 0)), "baby-6:4.9-3.x86_64");
+
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_goal_distupgrade_selector_nothing)
+{
+ HyGoal goal = hy_goal_create(test_globals.sack);
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "P-lib");
+ fail_if(hy_goal_distupgrade_selector(goal, sltr));
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 0, 0, 0, 0);
+ GPtrArray *plist = hy_goal_list_downgrades(goal, NULL);
+ fail_unless(plist->len == 0);
+ g_ptr_array_unref(plist);
+ hy_goal_free(goal);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_goal_rerun)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ DnfPackage *pkg = get_latest_pkg(sack, "walrus");
+
+ hy_goal_install(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 2, 0, 0, 0);
+ g_object_unref(pkg);
+
+ // add an erase:
+ pkg = by_name_repo(sack, "dog", HY_SYSTEM_REPO_NAME);
+ hy_goal_erase(goal, pkg);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 2, 0, 1, 0);
+ g_object_unref(pkg);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_unneeded)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+
+ userinstalled(sack, goal, "baby");
+ userinstalled(sack, goal, "bloop");
+ userinstalled(sack, goal, "dog");
+ userinstalled(sack, goal, "fool");
+ userinstalled(sack, goal, "gun");
+ userinstalled(sack, goal, "jay");
+ userinstalled(sack, goal, "penny");
+ userinstalled(sack, goal, "pilchard");
+ hy_goal_run_flags(goal, DNF_NONE);
+
+ GPtrArray *plist = hy_goal_list_unneeded(goal, NULL);
+ ck_assert_int_eq(plist->len, 4);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ assert_nevra_eq(pkg, "flying-2-9.noarch");
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ assert_nevra_eq(pkg, "penny-lib-4-1.x86_64");
+ g_ptr_array_unref(plist);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+struct Solutions {
+ int solutions;
+ GPtrArray *installs;
+};
+
+START_TEST(test_goal_installonly_limit)
+{
+ const char *installonly[] = {"k", NULL};
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 3);
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel_no);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 1, 1, 3, 0); // k-m is just upgraded
+ GPtrArray *erasures = hy_goal_list_erasures(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 0)), "k-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 1)),
+ "k-freak-1-0-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 2)), "k-1-1.x86_64");
+ g_ptr_array_unref(erasures);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_kernel_protected)
+{
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel);
+ Id kernel_id = mock_running_kernel(sack);
+ DnfPackage *kernel = dnf_package_new(sack, kernel_id);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_erase(goal, kernel);
+ fail_unless(hy_goal_run_flags(goal, DNF_NONE));
+
+ g_object_unref(kernel);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_installonly_limit_disabled)
+{
+ // test that setting limit to 0 does not cause all intallonlies to be
+ // uninstalled
+ const char *installonly[] = {"k", NULL};
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 0);
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel_no);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 1, 1, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+
+START_TEST(test_goal_installonly_limit_running_kernel)
+{
+ const char *installonly[] = {"k", NULL};
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 3);
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 1, 1, 3, 0);
+ GPtrArray *erasures = hy_goal_list_erasures(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 0)), "k-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 1)),
+ "k-freak-1-0-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 2)), "k-2-0.x86_64");
+ g_ptr_array_unref(erasures);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_installonly_limit_with_modules)
+{
+ // most complex installonly test case, includes the k-m packages
+ const char *installonly[] = {"k", "k-m", NULL};
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_installonly(sack, installonly);
+ dnf_sack_set_installonly_limit(sack, 3);
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel);
+
+ HyGoal goal = hy_goal_create(sack);
+ hy_goal_upgrade_all(goal);
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+
+ assert_iueo(goal, 2, 0, 5, 0);
+ GPtrArray *erasures = hy_goal_list_erasures(goal, NULL);
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 0)), "k-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 1)), "k-m-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 2)),
+ "k-freak-1-0-1-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 3)), "k-2-0.x86_64");
+ assert_nevra_eq(static_cast<DnfPackage *>(g_ptr_array_index(erasures, 4)), "k-m-2-0.x86_64");
+ g_ptr_array_unref(erasures);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_update_vendor)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "fool");
+ fail_if(hy_goal_upgrade_selector(goal, sltr));
+ hy_selector_free(sltr);
+
+ /* hy_goal_upgrade_all(goal); */
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 1, 0, 0, 1);
+
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_forcebest_arches)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+ HySelector sltr = hy_selector_create(sack);
+
+ hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "gun");
+ fail_if(hy_goal_upgrade_selector(goal, sltr));
+ fail_if(hy_goal_run_flags(goal, DNF_FORCE_BEST));
+ assert_iueo(goal, 0, 0, 0, 0);
+
+ hy_selector_free(sltr);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_change)
+{
+ // test that changes are handled like reinstalls
+
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_upgrade_all(goal);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 1, 0, 0);
+ fail_unless(size_and_free(hy_goal_list_reinstalls(goal, NULL)) == 1);
+ hy_goal_free(goal);
+}
+END_TEST
+
+START_TEST(test_goal_clone)
+{
+ DnfSack *sack = test_globals.sack;
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_upgrade_all(goal);
+ HyGoal goal2 = hy_goal_clone(goal);
+
+ fail_if(hy_goal_run_flags(goal, DNF_NONE));
+ assert_iueo(goal, 0, 1, 0, 0);
+ fail_unless(size_and_free(hy_goal_list_reinstalls(goal, NULL)) == 1);
+ hy_goal_free(goal);
+
+ fail_if(hy_goal_run_flags(goal2, DNF_NONE));
+ assert_iueo(goal2, 0, 1, 0, 0);
+ fail_unless(size_and_free(hy_goal_list_reinstalls(goal2, NULL)) == 1);
+ hy_goal_free(goal2);
+}
+END_TEST
+
+START_TEST(test_cmdline_file_provides)
+{
+ DnfSack *sack = test_globals.sack;
+ dnf_sack_set_running_kernel_fn(sack, mock_running_kernel_no);
+ HyGoal goal = hy_goal_create(sack);
+
+ hy_goal_upgrade_all(goal);
+ ck_assert(!hy_goal_run_flags(goal, DNF_FORCE_BEST));
+ assert_iueo(goal, 0, 1, 0, 0);
+ hy_goal_free(goal);
+}
+END_TEST
+
+Suite *
+goal_suite(void)
+{
+ Suite *s = suite_create("Goal");
+ TCase *tc;
+
+ tc = tcase_create("Core");
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ tcase_add_test(tc, test_goal_actions);
+ tcase_add_test(tc, test_goal_sanity);
+ tcase_add_test(tc, test_goal_list_err);
+ tcase_add_test(tc, test_goal_install);
+ tcase_add_test(tc, test_goal_install_multilib);
+ tcase_add_test(tc, test_goal_install_selector);
+ tcase_add_test(tc, test_goal_install_selector_err);
+ tcase_add_test(tc, test_goal_install_selector_two);
+ tcase_add_test(tc, test_goal_install_selector_nomatch);
+ tcase_add_test(tc, test_goal_install_optional);
+ tcase_add_test(tc, test_goal_selector_glob);
+ tcase_add_test(tc, test_goal_selector_provides_glob);
+ tcase_add_test(tc, test_goal_selector_upgrade_provides);
+ tcase_add_test(tc, test_goal_upgrade);
+ tcase_add_test(tc, test_goal_upgrade_all);
+ tcase_add_test(tc, test_goal_downgrade);
+ tcase_add_test(tc, test_goal_get_reason);
+ tcase_add_test(tc, test_goal_get_reason_selector);
+ tcase_add_test(tc, test_goal_describe_problem_rules);
+ tcase_add_test(tc, test_goal_distupgrade_all_keep_arch);
+ tcase_add_test(tc, test_goal_no_reinstall);
+ tcase_add_test(tc, test_goal_erase_simple);
+ tcase_add_test(tc, test_goal_erase_with_deps);
+ tcase_add_test(tc, test_goal_protected);
+ tcase_add_test(tc, test_goal_erase_clean_deps);
+ tcase_add_test(tc, test_goal_forcebest);
+ tcase_add_test(tc, test_goal_favor);
+ tcase_add_test(tc, test_goal_disfavor);
+ tcase_add_test(tc, test_goal_lock);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("ModifiesSackState");
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ tcase_add_checked_fixture(tc, fixture_reset, NULL);
+ tcase_add_test(tc, test_goal_installonly);
+ tcase_add_test(tc, test_goal_installonly_upgrade_all);
+ tcase_add_test(tc, test_goal_upgrade_all_excludes);
+ tcase_add_test(tc, test_goal_upgrade_disabled_repo);
+ tcase_add_test(tc, test_goal_describe_problem_excludes);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Main");
+ tcase_add_unchecked_fixture(tc, fixture_with_main, teardown);
+ tcase_add_test(tc, test_goal_distupgrade_all);
+ tcase_add_test(tc, test_goal_distupgrade_selector_upgrade);
+ tcase_add_test(tc, test_goal_distupgrade_selector_downgrade);
+ tcase_add_test(tc, test_goal_distupgrade_selector_nothing);
+ tcase_add_test(tc, test_goal_install_selector_file);
+ tcase_add_test(tc, test_goal_rerun);
+ tcase_add_test(tc, test_goal_unneeded);
+ tcase_add_test(tc, test_goal_distupgrade_all_excludes);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Greedy");
+ tcase_add_unchecked_fixture(tc, fixture_greedy_only, teardown);
+ tcase_add_test(tc, test_goal_install_weak_deps);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Installonly");
+ tcase_add_unchecked_fixture(tc, fixture_installonly, teardown);
+ tcase_add_checked_fixture(tc, fixture_reset, NULL);
+ tcase_add_test(tc, test_goal_installonly_limit);
+ tcase_add_test(tc, test_goal_installonly_limit_disabled);
+ tcase_add_test(tc, test_goal_installonly_limit_running_kernel);
+ tcase_add_test(tc, test_goal_installonly_limit_with_modules);
+ tcase_add_test(tc, test_goal_kernel_protected);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Vendor");
+ tcase_add_unchecked_fixture(tc, fixture_with_vendor, teardown);
+ tcase_add_test(tc, test_goal_update_vendor);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Forcebest");
+ tcase_add_unchecked_fixture(tc, fixture_with_forcebest, teardown);
+ tcase_add_test(tc, test_goal_forcebest_arches);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Change");
+ tcase_add_unchecked_fixture(tc, fixture_with_change, teardown);
+ tcase_add_test(tc, test_goal_change);
+ tcase_add_test(tc, test_goal_clone);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Cmdline");
+ tcase_add_unchecked_fixture(tc, fixture_with_cmdline, teardown);
+ tcase_add_test(tc, test_cmdline_file_provides);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Verify");
+ tcase_add_unchecked_fixture(tc, fixture_verify, teardown);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/hy-util.h"
+#include "libdnf/hy-iutil.h"
+#include "libdnf/hy-iutil-private.hpp"
+
+#include "fixtures.h"
+#include "test_suites.h"
+
+#include <solv/pool.h>
+#include <solv/repo.h>
+#include <solv/repo_write.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+
+static void
+build_test_file(const char *filename)
+{
+ FILE *fp = fopen(filename, "w+");
+ fail_if(fp == NULL);
+ fail_unless(fwrite("empty", 5, 1, fp) == 1);
+ fclose(fp);
+}
+
+START_TEST(test_abspath)
+{
+ char *abs = abspath("/cus/tard");
+ ck_assert_str_eq(abs, "/cus/tard");
+ g_free(abs);
+
+ abs = abspath("cus/tard");
+ ck_assert_int_eq(abs[0], '/');
+ g_free(abs);
+}
+END_TEST
+
+START_TEST(test_checksum)
+{
+ /* create a new file, edit it a bit */
+ char *new_file = solv_dupjoin(test_globals.tmpdir,
+ "/test_checksum", NULL);
+ build_test_file(new_file);
+
+ unsigned char cs1[CHKSUM_BYTES];
+ unsigned char cs2[CHKSUM_BYTES];
+ unsigned char cs1_sum[CHKSUM_BYTES];
+ unsigned char cs2_sum[CHKSUM_BYTES];
+ bzero(cs1, CHKSUM_BYTES);
+ bzero(cs2, CHKSUM_BYTES);
+ bzero(cs1_sum, CHKSUM_BYTES);
+ bzero(cs2_sum, CHKSUM_BYTES);
+ fail_if(checksum_cmp(cs1, cs2)); // tests checksum_cmp
+
+ /* take the first checksums */
+ FILE *fp;
+ fail_if((fp = fopen(new_file, "r")) == NULL);
+ fail_if(checksum_fp(cs1, fp));
+ fail_if(checksum_stat(cs1_sum, fp));
+ fclose(fp);
+ /* the taken checksum are not zeros anymore */
+ fail_if(checksum_cmp(cs1, cs2) == 0);
+ fail_if(checksum_cmp(cs1_sum, cs2_sum) == 0);
+ fp = NULL;
+
+ /* append something */
+ fail_if((fp = fopen(new_file, "a")) == NULL);
+ fail_unless(fwrite("X", 1, 1, fp) == 1);
+ fclose(fp);
+ fp = NULL;
+
+ /* take the second checksums */
+ fail_if((fp = fopen(new_file, "r")) == NULL);
+ fail_if(checksum_stat(cs2, fp));
+ fail_if(checksum_stat(cs2_sum, fp));
+ fclose(fp);
+ fail_unless(checksum_cmp(cs1, cs2));
+ fail_unless(checksum_cmp(cs1_sum, cs2_sum));
+
+ g_free(new_file);
+}
+END_TEST
+
+START_TEST(test_dnf_solvfile_userdata)
+{
+ char *new_file = solv_dupjoin(test_globals.tmpdir,
+ "/test_dnf_solvfile_userdata", NULL);
+ build_test_file(new_file);
+
+ unsigned char cs_computed[CHKSUM_BYTES];
+ FILE *fp = fopen(new_file, "r+");
+ checksum_fp(cs_computed, fp);
+
+ SolvUserdata solv_userdata;
+ fail_if(solv_userdata_fill(&solv_userdata, cs_computed, NULL));
+
+ Pool *pool = pool_create();
+ Repo *repo = repo_create(pool, "test_repo");
+ Repowriter *writer = repowriter_create(repo);
+ repowriter_set_userdata(writer, &solv_userdata, solv_userdata_size);
+ fail_if(repowriter_write(writer, fp));
+ repowriter_free(writer);
+ fclose(fp);
+
+ fp = fopen(new_file, "r");
+ std::unique_ptr<SolvUserdata, decltype(solv_free)*> dnf_solvfile = solv_userdata_read(fp);
+ fail_unless(dnf_solvfile);
+ fail_unless(solv_userdata_verify(dnf_solvfile.get(), cs_computed));
+ fclose(fp);
+
+ g_free(new_file);
+ repo_free(repo, 0);
+ pool_free(pool);
+}
+END_TEST
+
+START_TEST(test_mkcachedir)
+{
+ const char *workdir = test_globals.tmpdir;
+ char * dir;
+ fail_if(asprintf(&dir, "%s%s", workdir, "/mkcachedir/sub/deep") == -1);
+ fail_if(mkcachedir(dir));
+ fail_if(access(dir, R_OK|X_OK|W_OK));
+ free(dir);
+
+ fail_if(asprintf(&dir, "%s%s", workdir, "/mkcachedir/sub2/wd-XXXXXX") == -1);
+ fail_if(mkcachedir(dir));
+ fail_if(g_str_has_suffix(dir, "XXXXXX")); /* mkcache dir changed the Xs */
+ fail_if(access(dir, R_OK|X_OK|W_OK));
+
+ /* test the globbing capability of mkcachedir */
+ char *dir2;
+ fail_if(asprintf(&dir2, "%s%s", workdir, "/mkcachedir/sub2/wd-XXXXXX") == -1);
+ fail_if(mkcachedir(dir2));
+ fail_if(strcmp(dir, dir2)); /* mkcachedir should have arrived at the same name */
+
+ free(dir2);
+ free(dir);
+}
+END_TEST
+
+START_TEST(test_version_split)
+{
+ Pool *pool = pool_create();
+ char evr[] = "1:5.9.3-8";
+ char *epoch, *version, *release;
+
+ pool_split_evr(pool, evr, &epoch, &version, &release);
+ ck_assert_str_eq(epoch, "1");
+ ck_assert_str_eq(version, "5.9.3");
+ ck_assert_str_eq(release, "8");
+
+ char evr2[] = "8.0-9";
+ pool_split_evr(pool, evr2, &epoch, &version, &release);
+ fail_unless(epoch == NULL);
+ ck_assert_str_eq(version, "8.0");
+ ck_assert_str_eq(release, "9");
+
+ char evr3[] = "1.4";
+ pool_split_evr(pool, evr3, &epoch, &version, &release);
+ fail_unless(epoch == NULL);
+ ck_assert_str_eq(version, "1.4");
+ fail_unless(release == NULL);
+
+ pool_free(pool);
+}
+END_TEST
+
+Suite *
+iutil_suite(void)
+{
+ Suite *s = suite_create("iutil");
+ TCase *tc = tcase_create("Main");
+ tcase_add_test(tc, test_abspath);
+ tcase_add_test(tc, test_checksum);
+ tcase_add_test(tc, test_dnf_solvfile_userdata);
+ tcase_add_test(tc, test_mkcachedir);
+ tcase_add_test(tc, test_version_split);
+ suite_add_tcase(s, tc);
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+#include <solv/util.h>
+
+#include <assert.h>
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define TESTREPODATADIR TESTDATADIR "/hawkey"
+
+static int
+init_test_globals(struct TestGlobals_s *tg, const char *repo_dir)
+{
+ int const len = strlen(repo_dir);
+ if (repo_dir[len -1] != '/')
+ tg->repo_dir = solv_dupjoin(repo_dir, "/", NULL);
+ else
+ tg->repo_dir = g_strdup(repo_dir);
+ tg->tmpdir = g_strdup(UNITTEST_DIR);
+ if (mkdtemp(tg->tmpdir) == NULL)
+ return 1;
+ tg->sack = NULL;
+ return 0;
+}
+
+static void
+free_test_globals(struct TestGlobals_s *tg)
+{
+ g_free(tg->tmpdir);
+ g_free(tg->repo_dir);
+}
+
+int
+main(int argc, const char **argv)
+{
+ int number_failed;
+
+ if (init_test_globals(&test_globals, TESTREPODATADIR)) {
+ fprintf(stderr, "failed initializing test engine.\n");
+ exit(1);
+ }
+ printf("Tests using directory: %s\n", test_globals.tmpdir);
+
+ SRunner *sr = srunner_create(sack_suite());
+ srunner_add_suite(sr, iutil_suite());
+ srunner_add_suite(sr, util_suite());
+ srunner_add_suite(sr, reldep_suite());
+ srunner_add_suite(sr, repo_suite());
+ srunner_add_suite(sr, package_suite());
+ srunner_add_suite(sr, packagelist_suite());
+ srunner_add_suite(sr, packageset_suite());
+ srunner_add_suite(sr, query_suite());
+ srunner_add_suite(sr, selector_suite());
+ srunner_add_suite(sr, subject_suite());
+ srunner_add_suite(sr, goal_suite());
+ srunner_add_suite(sr, advisory_suite());
+ srunner_add_suite(sr, advisorypkg_suite());
+ srunner_add_suite(sr, advisoryref_suite());
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ free_test_globals(&test_globals);
+ return (number_failed == 0) ? 0 : 1;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+#include "libdnf/dnf-advisory.h"
+#include "libdnf/hy-package.h"
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-query.h"
+#include "libdnf/dnf-reldep.h"
+#include "libdnf/dnf-reldep-list.h"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-util.h"
+#include "libdnf/repo/solvable/Dependency.hpp"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+#include <solv/util.h>
+
+START_TEST(test_package_summary)
+{
+ DnfPackage *pkg = by_name(test_globals.sack, "penny-lib");
+ fail_if(strcmp(dnf_package_get_summary(pkg), "in my ears"));
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_identical)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg1 = by_name(sack, "penny-lib");
+ DnfPackage *pkg2 = by_name(sack, "flying");
+ DnfPackage *pkg3 = by_name(sack, "penny-lib");
+
+ fail_unless(dnf_package_get_identical(pkg1, pkg3));
+ fail_if(dnf_package_get_identical(pkg2, pkg3));
+
+ g_object_unref(pkg1);
+ g_object_unref(pkg2);
+ g_object_unref(pkg3);
+}
+END_TEST
+
+START_TEST(test_versions)
+{
+ DnfSack *sack = test_globals.sack;
+ unsigned epoch;
+ const char *version, *release;
+ DnfPackage *pkg;
+
+ pkg = by_name(sack, "baby");
+ ck_assert_str_eq(dnf_package_get_evr(pkg), "6:5.0-11");
+ epoch = dnf_package_get_epoch(pkg);
+ fail_unless(epoch == 6);
+ version = dnf_package_get_version(pkg);
+ ck_assert_str_eq(version, "5.0");
+ release = dnf_package_get_release(pkg);
+ ck_assert_str_eq(release, "11");
+ g_object_unref(pkg);
+
+ pkg = by_name(sack, "jay");
+ // epoch missing if it's 0:
+ ck_assert_str_eq(dnf_package_get_evr(pkg), "5.0-0");
+ epoch = dnf_package_get_epoch(pkg);
+ fail_unless(epoch == 0);
+ version = dnf_package_get_version(pkg);
+ ck_assert_str_eq(version, "5.0");
+ release = dnf_package_get_release(pkg);
+ ck_assert_str_eq(release, "0");
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_vendor)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name_repo(sack, "foolish-grin", "vendor");
+ fail_if(pkg == NULL);
+ const char *vendor = dnf_package_get_vendor(pkg);
+
+ ck_assert_str_eq(vendor, "PerfectlyLoud");
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_no_sourcerpm)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "baby");
+ const char *src = dnf_package_get_sourcerpm(pkg);
+
+ fail_unless(src == NULL);
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_get_requires)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "flying");
+ DnfReldepList *reldeplist = dnf_package_get_requires(pkg);
+
+ fail_unless(dnf_reldep_list_count (reldeplist) == 1);
+ DnfReldep *reldep = dnf_reldep_list_index (reldeplist, 0);
+
+ const char *depstr = dnf_reldep_to_string (reldep);
+ ck_assert_str_eq(depstr, "P-lib >= 3");
+
+ delete reldep;
+ delete reldeplist;
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_get_more_requires)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "walrus");
+ DnfReldepList *reldeplist = dnf_package_get_requires(pkg);
+
+ fail_unless(dnf_reldep_list_count (reldeplist) == 2);
+ delete reldeplist;
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_chksum_fail)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "walrus");
+ int type;
+
+ const unsigned char *chksum = dnf_package_get_chksum(pkg, &type);
+ fail_unless(chksum == NULL);
+ chksum = dnf_package_get_hdr_chksum(pkg, &type);
+ fail_unless(chksum == NULL);
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_checksums)
+{
+ DnfPackage *pkg = by_name(test_globals.sack, "mystery-devel");
+ int i;
+ HyChecksum *csum = dnf_package_get_chksum(pkg, &i);
+ fail_unless(i == G_CHECKSUM_SHA256);
+ // Check the first and last bytes. Those need to match against information
+ // in primary.xml.gz.
+ fail_unless(csum[0] == 0x2e);
+ fail_unless(csum[31] == 0xf5);
+
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_get_files)
+{
+ DnfSack *sack = test_globals.sack;
+
+ DnfPackage *pkg = by_name(sack, "tour");
+ gchar **files = dnf_package_get_files(pkg);
+ int i = 0;
+ char **iter;
+
+ for (iter = files; iter && *iter; iter++)
+ i++;
+ g_assert_cmpint(i, ==, 6);
+ g_strfreev(files);
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_get_advisories)
+{
+ GPtrArray *advisories;
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "tour");
+
+ advisories = dnf_package_get_advisories(pkg, HY_GT);
+ fail_unless(advisories != NULL);
+ ck_assert_int_eq(advisories->len, 1);
+ auto advisory = static_cast<DnfAdvisory *>(g_ptr_array_index(advisories, 0));
+ ck_assert_str_eq(dnf_advisory_get_id(advisory), "FEDORA-2008-9969");
+ g_ptr_array_unref(advisories);
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_get_advisories_none)
+{
+ GPtrArray *advisories;
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg = by_name(sack, "mystery-devel");
+
+ advisories = dnf_package_get_advisories(pkg, HY_GT|HY_EQ);
+ fail_unless(advisories != NULL);
+ ck_assert_int_eq(advisories->len, 1);
+ g_ptr_array_unref(advisories);
+
+ advisories = dnf_package_get_advisories(pkg, HY_LT|HY_EQ);
+ fail_unless(advisories != NULL);
+ ck_assert_int_eq(advisories->len, 1);
+ g_ptr_array_unref(advisories);
+
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_lookup_num)
+{
+ DnfPackage *pkg = by_name(test_globals.sack, "tour");
+ guint64 buildtime = dnf_package_get_buildtime(pkg);
+ fail_unless(buildtime > 1330473600); // after 2012-02-29
+ fail_unless(buildtime < 1456704000); // before 2016-02-29
+
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_installed)
+{
+ DnfPackage *pkg1 = by_name_repo(test_globals.sack, "penny-lib", "main");
+ DnfPackage *pkg2 = by_name_repo(test_globals.sack,
+ "penny-lib", HY_SYSTEM_REPO_NAME);
+ int installed1 = dnf_package_installed(pkg1);
+ int installed2 = dnf_package_installed(pkg2);
+ fail_unless(installed1 == 0);
+ fail_unless(installed2 == 1);
+
+ g_object_unref(pkg1);
+ g_object_unref(pkg2);
+}
+END_TEST
+
+START_TEST(test_two_sacks)
+{
+ /* This clumsily mimics create_ut_sack() and setup_with() to
+ * create a second DnfSack. */
+ char *tmpdir = solv_dupjoin(test_globals.tmpdir, "/tmp", NULL);
+ DnfSack *sack1 = dnf_sack_new();
+ dnf_sack_set_arch(sack1, TEST_FIXED_ARCH, NULL);
+ dnf_sack_set_cachedir(sack1, tmpdir);
+ fail_unless(dnf_sack_setup(sack1, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ Pool *pool1 = dnf_sack_get_pool(sack1);
+ const char *path = pool_tmpjoin(pool1, test_globals.repo_dir,
+ "change.repo", NULL);
+ fail_if(load_repo(pool1, "change", path, 0));
+ DnfPackage *pkg1 = by_name(sack1, "penny-lib");
+ fail_if(pkg1 == NULL);
+
+ DnfSack *sack2 = test_globals.sack;
+ Pool *pool2 = dnf_sack_get_pool(sack2);
+ DnfPackage *pkg2 = by_name(sack2, "penny-lib");
+ fail_if(pkg2 == NULL);
+
+ /* "penny-lib" is in both pools but at different offsets */
+ Solvable *s1 = pool_id2solvable(pool1, dnf_package_get_id(pkg1));
+ Solvable *s2 = pool_id2solvable(pool2, dnf_package_get_id(pkg2));
+ fail_if(s1->name == s2->name);
+
+ fail_if(dnf_package_cmp(pkg1, pkg2) != 0);
+
+ g_object_unref(pkg1);
+ g_object_unref(pkg2);
+
+ g_object_unref(sack1);
+ g_free(tmpdir);
+}
+END_TEST
+
+START_TEST(test_packager)
+{
+ DnfPackage *pkg = by_name(test_globals.sack, "tour");
+ ck_assert_str_eq(dnf_package_get_packager(pkg), "roll up <roll@up.net>");
+ g_object_unref(pkg);
+}
+END_TEST
+
+START_TEST(test_sourcerpm)
+{
+ DnfPackage *pkg = by_name(test_globals.sack, "tour");
+ const char *sourcerpm = dnf_package_get_sourcerpm(pkg);
+
+ ck_assert_str_eq(sourcerpm, "tour-4-6.src.rpm");
+ g_object_unref(pkg);
+
+ pkg = by_name(test_globals.sack, "mystery-devel");
+ sourcerpm = dnf_package_get_sourcerpm(pkg);
+ ck_assert_str_eq(sourcerpm, "mystery-19.67-1.src.rpm");
+ g_object_unref(pkg);
+}
+END_TEST
+
+#define TOUR_45_46_DRPM_CHKSUM "\xc3\xc3\xd5\x72\xa4\x6b"\
+ "\x1a\x66\x90\x6d\x42\xca\x17\x63\xef\x36\x20\xf7\x02"\
+ "\x58\xaa\xac\x4c\x14\xbf\x46\x3e\xd5\x37\x16\xd4\x44"
+
+START_TEST(test_presto)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *tour = by_name(sack, "tour");
+ fail_if(tour == NULL);
+
+ DnfPackageDelta *delta = dnf_package_get_delta_from_evr(tour, "4-5");
+ const char *location = dnf_packagedelta_get_location(delta);
+ ck_assert_str_eq(location, "drpms/tour-4-5_4-6.noarch.drpm");
+ const char *baseurl = dnf_packagedelta_get_baseurl(delta);
+ fail_unless(baseurl == NULL);
+ guint64 size = dnf_packagedelta_get_downloadsize(delta);
+ ck_assert_int_eq(size, 3132);
+ int type;
+ HyChecksum *csum = dnf_packagedelta_get_chksum(delta, &type);
+ fail_unless(type == G_CHECKSUM_SHA256);
+ ck_assert(!memcmp(csum, TOUR_45_46_DRPM_CHKSUM, 32));
+ g_object_unref(delta);
+ g_object_unref(tour);
+}
+END_TEST
+
+START_TEST(test_get_files_cmdline)
+{
+ DnfSack *sack = test_globals.sack;
+
+ DnfPackage *pkg = by_name(sack, "tour");
+ gchar **files;
+
+ files = dnf_package_get_files(pkg);
+ g_assert_cmpint (6, ==, g_strv_length(files));
+ g_strfreev(files);
+ g_object_unref(pkg);
+}
+END_TEST
+
+Suite *
+package_suite(void)
+{
+ Suite *s = suite_create("Package");
+ TCase *tc;
+
+ tc = tcase_create("Core");
+ tcase_add_unchecked_fixture(tc, fixture_system_only, teardown);
+ tcase_add_test(tc, test_package_summary);
+ tcase_add_test(tc, test_identical);
+ tcase_add_test(tc, test_versions);
+ tcase_add_test(tc, test_no_sourcerpm);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Requires");
+ tcase_add_unchecked_fixture(tc, fixture_with_main, teardown);
+ tcase_add_test(tc, test_get_requires);
+ tcase_add_test(tc, test_get_more_requires);
+ tcase_add_test(tc, test_chksum_fail);
+ tcase_add_test(tc, test_installed);
+ tcase_add_test(tc, test_two_sacks);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("WithRealRepo");
+ tcase_add_unchecked_fixture(tc, fixture_yum, teardown);
+ tcase_add_test(tc, test_checksums);
+ tcase_add_test(tc, test_get_files);
+ tcase_add_test(tc, test_get_advisories);
+ tcase_add_test(tc, test_get_advisories_none);
+ tcase_add_test(tc, test_lookup_num);
+ tcase_add_test(tc, test_packager);
+ tcase_add_test(tc, test_sourcerpm);
+ tcase_add_test(tc, test_presto);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("WithCmdlinePackage");
+ tcase_add_unchecked_fixture(tc, fixture_cmdline_only, teardown);
+ tcase_add_test(tc, test_get_files_cmdline);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Vendor");
+ tcase_add_unchecked_fixture(tc, fixture_with_vendor, teardown);
+ tcase_add_test(tc, test_vendor);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-util-private.hpp"
+#include "test_suites.h"
+
+static DnfPackage *
+mock_package(Id id)
+{
+ return dnf_package_new(NULL, id);
+}
+
+static GPtrArray *fixture_plist;
+
+static void
+create_fixture(void)
+{
+ fixture_plist = hy_packagelist_create();
+ g_ptr_array_add(fixture_plist, mock_package(10));
+ g_ptr_array_add(fixture_plist, mock_package(11));
+ g_ptr_array_add(fixture_plist, mock_package(12));
+}
+
+static void
+free_fixture(void)
+{
+ g_ptr_array_unref(fixture_plist);
+}
+
+START_TEST(test_has)
+{
+ DnfPackage *pkg1 = mock_package(10);
+ DnfPackage *pkg2 = mock_package(1);
+
+ fail_unless(hy_packagelist_has(fixture_plist, pkg1));
+ fail_if(hy_packagelist_has(fixture_plist, pkg2));
+
+ g_object_unref(pkg1);
+ g_object_unref(pkg2);
+}
+END_TEST
+
+Suite *
+packagelist_suite(void)
+{
+ Suite *s = suite_create("PackageList");
+
+ TCase *tc = tcase_create("Core");
+ tcase_add_unchecked_fixture(tc, create_fixture, free_fixture);
+ tcase_add_test(tc, test_has);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-packageset-private.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/sack/packageset.hpp"
+
+#include "fixtures.h"
+#include "test_suites.h"
+
+static DnfPackageSet *pset;
+
+static void
+packageset_fixture(void)
+{
+ fixture_all();
+
+ DnfSack *sack = test_globals.sack;
+ g_autoptr(DnfPackage) pkg0 = dnf_package_new(sack, 0);
+ g_autoptr(DnfPackage) pkg9 = dnf_package_new(sack, 9);
+ int max = dnf_sack_last_solvable(sack);
+ g_autoptr(DnfPackage) pkg_max = dnf_package_new(sack, max);
+
+ // init the global var
+ pset = dnf_packageset_new(sack);
+
+ dnf_packageset_add(pset, pkg0);
+ dnf_packageset_add(pset, pkg9);
+ dnf_packageset_add(pset, pkg_max);
+
+}
+
+static void
+packageset_teardown(void)
+{
+ delete pset;
+ teardown();
+}
+
+START_TEST(test_clone)
+{
+ DnfSack *sack = test_globals.sack;
+ auto pset2 = std::unique_ptr <DnfPackageSet> (dnf_packageset_clone(pset));
+
+ DnfPackage *pkg8 = dnf_package_new(sack, 8);
+ DnfPackage *pkg9 = dnf_package_new(sack, 9);
+
+ fail_if(dnf_packageset_has(pset2.get(), pkg8));
+ fail_unless(dnf_packageset_has(pset2.get(), pkg9));
+
+ g_object_unref(pkg8);
+ g_object_unref(pkg9);
+}
+END_TEST
+
+START_TEST(test_has)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *pkg0 = dnf_package_new(sack, 0);
+ DnfPackage *pkg9 = dnf_package_new(sack, 9);
+ DnfPackage *pkg_max = dnf_package_new(sack, dnf_sack_last_solvable(sack));
+
+ DnfPackage *pkg7 = dnf_package_new(sack, 7);
+ DnfPackage *pkg8 = dnf_package_new(sack, 8);
+ DnfPackage *pkg15 = dnf_package_new(sack, 15);
+
+ fail_unless(dnf_packageset_has(pset, pkg0));
+ fail_unless(dnf_packageset_has(pset, pkg9));
+ fail_unless(dnf_packageset_has(pset, pkg_max));
+ fail_if(dnf_packageset_has(pset, pkg7));
+ fail_if(dnf_packageset_has(pset, pkg8));
+ fail_if(dnf_packageset_has(pset, pkg15));
+
+ g_object_unref(pkg0);
+ g_object_unref(pkg9);
+ g_object_unref(pkg_max);
+ g_object_unref(pkg7);
+ g_object_unref(pkg8);
+ g_object_unref(pkg15);
+
+}
+END_TEST
+
+START_TEST(test_get_clone)
+{
+ DnfSack *sack = test_globals.sack;
+ int max = dnf_sack_last_solvable(sack);
+
+ fail_unless(dnf_packageset_count(pset) == 3);
+ DnfPackage *pkg0 = dnf_package_new(pset->getSack(), (*pset)[0]);
+ DnfPackage *pkg9 = dnf_package_new(pset->getSack(), (*pset)[1]);
+ DnfPackage *pkg_max = dnf_package_new(pset->getSack(), (*pset)[2]);
+ fail_unless(dnf_package_get_id(pkg0) == 0);
+ fail_unless(dnf_package_get_id(pkg9) == 9);
+ fail_unless(dnf_package_get_id(pkg_max) == max);
+ //fail_unless(dnf_package_new(pset->getSack(), (*pset)[3]) == NULL);
+
+ g_object_unref(pkg0);
+ g_object_unref(pkg9);
+ g_object_unref(pkg_max);
+
+ DnfPackage *pkg8 = dnf_package_new(sack, 8);
+ DnfPackage *pkg11 = dnf_package_new(sack, 11);
+ dnf_packageset_add(pset, pkg8);
+ dnf_packageset_add(pset, pkg11);
+ g_object_unref(pkg8);
+ g_object_unref(pkg11);
+ pkg8 = dnf_package_new(pset->getSack(), (*pset)[1]);
+ pkg9 = dnf_package_new(pset->getSack(), (*pset)[2]);
+ pkg11 = dnf_package_new(pset->getSack(), (*pset)[3]);
+ fail_unless(dnf_package_get_id(pkg8) == 8);
+ fail_unless(dnf_package_get_id(pkg9) == 9);
+ fail_unless(dnf_package_get_id(pkg11) == 11);
+
+ g_object_unref(pkg8);
+ g_object_unref(pkg9);
+ g_object_unref(pkg11);
+}
+END_TEST
+
+START_TEST(test_get_pkgid)
+{
+ DnfSack *sack = test_globals.sack;
+ int max = dnf_sack_last_solvable(sack);
+
+ // add some more packages
+ DnfPackage *pkg;
+ pkg = dnf_package_new(sack, 7);
+ dnf_packageset_add(pset, pkg);
+ g_object_unref(pkg);
+ pkg = dnf_package_new(sack, 8);
+ dnf_packageset_add(pset, pkg);
+ g_object_unref(pkg);
+ pkg = dnf_package_new(sack, 15);
+ dnf_packageset_add(pset, pkg);
+ g_object_unref(pkg);
+
+ Id id = -1;
+ id = pset->next(id);
+ fail_unless(id == 0);
+ id = pset->next(id);
+ fail_unless(id == 7);
+ id = pset->next(id);
+ fail_unless(id == 8);
+ id = pset->next(id);
+ fail_unless(id == 9);
+ id = pset->next(id);
+ fail_unless(id == 15);
+ id = (*pset)[5];
+ fail_unless(id == max);
+}
+END_TEST
+
+Suite *
+packageset_suite(void)
+{
+ Suite *s = suite_create("PackageSet");
+
+ TCase *tc = tcase_create("Core");
+ tcase_add_checked_fixture(tc, packageset_fixture, packageset_teardown);
+ tcase_add_test(tc, test_clone);
+ tcase_add_test(tc, test_has);
+ tcase_add_test(tc, test_get_clone);
+ tcase_add_test(tc, test_get_pkgid);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/hy-query.h"
+#include "libdnf/hy-query-private.hpp"
+#include "libdnf/hy-package.h"
+#include "libdnf/hy-packageset.h"
+#include "libdnf/dnf-reldep.h"
+#include "libdnf/dnf-reldep-list.h"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+#include "libdnf/sack/packageset.hpp"
+#include "libdnf/sack/query.hpp"
+
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+#include <solv/testcase.h>
+
+#include <check.h>
+
+
+static int
+size_and_free(HyQuery query)
+{
+ int c = query_count_results(query);
+ hy_query_free(query);
+ return c;
+}
+
+START_TEST(test_query_sanity)
+{
+ DnfSack *sack = test_globals.sack;
+ fail_unless(sack != NULL);
+ fail_unless(dnf_sack_count(sack) == TEST_EXPECT_SYSTEM_NSOLVABLES);
+ fail_unless(dnf_sack_get_pool(sack)->installed != NULL);
+
+ HyQuery query = hy_query_create(sack);
+ fail_unless(query != NULL);
+ hy_query_free(query);
+}
+END_TEST
+
+START_TEST(test_query_run_set_sanity)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q = hy_query_create(sack);
+ DnfPackageSet *pset = hy_query_run_set(q);
+
+ // make sure we are testing with some odd bits in the underlying map:
+ fail_unless(TEST_EXPECT_SYSTEM_NSOLVABLES % 8);
+ fail_unless(dnf_packageset_count(pset) == TEST_EXPECT_SYSTEM_NSOLVABLES);
+ delete pset;
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_clear)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_NEQ, "fool");
+ hy_query_clear(q);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "fool");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_clone)
+{
+ const char *namelist[] = {"penny", "fool", NULL};
+ HyQuery q = hy_query_create(test_globals.sack);
+
+ hy_query_filter_in(q, HY_PKG_NAME, HY_EQ, namelist);
+ HyQuery clone = hy_query_clone(q);
+ hy_query_free(q);
+ fail_unless(query_count_results(clone) == 2);
+ hy_query_free(clone);
+}
+END_TEST
+
+START_TEST(test_query_empty)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_if(hy_query_filter_empty(q));
+ fail_unless(query_count_results(q) == 0);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_repo)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
+
+ fail_unless(query_count_results(q) == TEST_EXPECT_SYSTEM_NSOLVABLES);
+
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_NEQ, HY_SYSTEM_REPO_NAME);
+ fail_if(query_count_results(q));
+
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_installed_available)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ q->installed();
+
+ fail_unless(query_count_results(q) == TEST_EXPECT_SYSTEM_NSOLVABLES);
+
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ q->available();
+ fail_if(query_count_results(q));
+
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_name)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_SUBSTR, "penny");
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "lane");
+ fail_if(query_count_results(q));
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_evr)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_EVR, HY_EQ, "6.0-0");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_EVR, HY_GT, "5.9-0");
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_EVR, HY_GT|HY_EQ, "5.0-0");
+ fail_unless(query_count_results(q) == 3);
+ hy_query_free(q);
+
+ const char *evrs[] = {"6.0-0", "2-9", "5.0-0", "0-100", NULL};
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter_in(q, HY_PKG_EVR, HY_EQ, evrs);
+ fail_unless(query_count_results(q) == 3);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_epoch)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_unless(hy_query_filter(q, HY_PKG_EPOCH, HY_GT|HY_EQ, "1"));
+ fail_if(hy_query_filter_num(q, HY_PKG_EPOCH, HY_GT|HY_EQ, 1));
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_version)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_VERSION, HY_EQ, "5.0");
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_VERSION, HY_GT, "5.2.1");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_VERSION, HY_GT|HY_EQ, "5.");
+ fail_unless(query_count_results(q) == 3);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_location)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_unless(hy_query_filter(q, HY_PKG_LOCATION, HY_GT,
+ "tour-4-6.noarch.rpm"));
+ fail_if(hy_query_filter(q, HY_PKG_LOCATION, HY_EQ,
+ "tour-4-6.noarch.rpm"));
+ fail_unless(size_and_free(q) == 1);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_LOCATION, HY_EQ,
+ "mystery-devel-19.67-1.noarch.rpm");
+ fail_unless(size_and_free(q) == 1);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_LOCATION, HY_EQ,
+ "mystery-19.67-1.src.rpm");
+ fail_unless(size_and_free(q) == 0);
+}
+END_TEST
+
+START_TEST(test_query_release)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_RELEASE, HY_EQ, "11");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_RELEASE, HY_GT, "9");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_RELEASE, HY_GT|HY_EQ, "9");
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_glob)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_GLOB, "pen*");
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_case)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "Penny-lib");
+ fail_unless(query_count_results(q) == 0);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ|HY_ICASE, "Penny-lib");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_anded)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_SUBSTR, "penny");
+ hy_query_filter(q, HY_PKG_SUMMARY, HY_SUBSTR, "ears");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_neq)
+{
+ HyQuery q;
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_NEQ, "penny-lib");
+ fail_unless(query_count_results(q) == TEST_EXPECT_SYSTEM_PKGS - 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_in)
+{
+ HyQuery q;
+ const char *namelist[] = {"penny", "fool", NULL};
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter_in(q, HY_PKG_NAME, HY_EQ, namelist);
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_pkg)
+{
+ DnfPackageSet *pset;
+ HyQuery q, q2;
+
+ // setup
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ pset = hy_query_run_set(q);
+ hy_query_free(q);
+ fail_unless(dnf_packageset_count(pset) == 2);
+
+ // use hy_query_filter_package_in():
+ q = hy_query_create(test_globals.sack);
+ // check validation works:
+ fail_unless(hy_query_filter_package_in(q, HY_PKG, HY_GT, pset));
+ // add the filter:
+ fail_if(hy_query_filter_package_in(q, HY_PKG, HY_EQ, pset));
+ delete pset;
+
+ // cloning must work
+ q2 = hy_query_clone(q);
+ fail_unless(query_count_results(q) == 2);
+ hy_query_free(q);
+
+ // filter on
+ hy_query_filter_latest_per_arch(q2, 1);
+ pset = hy_query_run_set(q2);
+ fail_unless(dnf_packageset_count(pset) == 1);
+ DnfPackage *pkg = dnf_package_new(pset->getSack(), (*pset)[0]);
+ const char *nvra = dnf_package_get_nevra(pkg);
+ ck_assert_str_eq(nvra, "jay-6.0-0.x86_64");
+ g_object_unref(pkg);
+
+ delete pset;
+ hy_query_free(q2);
+}
+END_TEST
+
+START_TEST(test_query_provides)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+
+ q = hy_query_create(sack);
+ hy_query_filter_provides(q, HY_LT, "fool", "2.0");
+ fail_unless(size_and_free(q) == 1);
+
+ q = hy_query_create(sack);
+ hy_query_filter_provides(q, HY_GT, "fool", "2.0");
+ fail_unless(size_and_free(q) == 0);
+
+ q = hy_query_create(sack);
+ hy_query_filter_provides(q, HY_EQ, "P", "3-3");
+ fail_unless(size_and_free(q) == 1);
+}
+END_TEST
+
+START_TEST(test_query_recommends)
+{
+ GPtrArray *plist;
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_RECOMMENDS, HY_EQ, "baby");
+ plist = hy_query_run(q);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "flying");
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_query_suggests)
+{
+ GPtrArray *plist;
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SUGGESTS, HY_EQ, "walrus");
+ plist = hy_query_run(q);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "flying");
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_query_supplements)
+{
+ GPtrArray *plist;
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SUPPLEMENTS, HY_EQ, "flying");
+ plist = hy_query_run(q);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "baby");
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_query_enhances)
+{
+ GPtrArray *plist;
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ENHANCES, HY_EQ, "flying");
+ plist = hy_query_run(q);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "walrus");
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_query_provides_in)
+{
+ GPtrArray *plist;
+ const char* pkg_names[] = { "P", "fool <= 2.0", "fool-lib > 3-3", NULL };
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter_provides_in(q, (char**) pkg_names);
+ plist = hy_query_run(q);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "fool");
+ ck_assert_str_eq(dnf_package_get_evr(pkg), "1-3");
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "penny");
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 2));
+ ck_assert_str_eq(dnf_package_get_name(pkg), "fool");
+ ck_assert_str_eq(dnf_package_get_evr(pkg), "1-5");
+ fail_unless(size_and_free(q) == 3);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_query_provides_in_not_found)
+{
+ GPtrArray *plist;
+ const char* provides[] = { "thisisnotgoingtoexist", NULL };
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter_provides_in(q, (char**) provides);
+ plist = hy_query_run(q);
+ fail_unless(plist->len == 0);
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_fileprovides)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_FILE, HY_EQ, "/no/answers");
+ fail_unless(query_count_results(q) == 1);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_conflicts)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q = hy_query_create(sack);
+ DnfReldep *reldep = dnf_reldep_new(sack, "custard", HY_GT|HY_EQ, "1.0.1");
+
+ fail_unless(reldep != NULL);
+ hy_query_filter_reldep(q, HY_PKG_CONFLICTS, reldep);
+ fail_unless(query_count_results(q) == 1);
+
+ delete reldep;
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_upgrades_sanity)
+{
+ Pool *pool = dnf_sack_get_pool(test_globals.sack);
+ Repo *r = NULL;
+ int i;
+
+ FOR_REPOS(i, r)
+ if (!strcmp(r->name, "updates"))
+ break;
+ fail_unless(r != NULL);
+ fail_unless(r->nsolvables == TEST_EXPECT_UPDATES_NSOLVABLES);
+}
+END_TEST
+
+START_TEST(test_upgrades)
+{
+ const char *installonly[] = {"fool", NULL};
+ dnf_sack_set_installonly(test_globals.sack, installonly);
+
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter_upgrades(q, 1);
+ fail_unless(query_count_results(q) == TEST_EXPECT_UPDATES_NSOLVABLES - 8);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_upgradable)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter_upgradable(q, 1);
+ ck_assert_int_eq(query_count_results(q), 6);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_latest)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "fool");
+ hy_query_filter_latest_per_arch(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ fail_if(strcmp(dnf_package_get_name(pkg), "fool"));
+ fail_if(strcmp(dnf_package_get_evr(pkg), "1-5"));
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_filter_latest2)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "flying");
+ hy_query_filter_latest_per_arch(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ fail_if(strcmp(dnf_package_get_name(pkg), "flying"));
+ fail_if(strcmp(dnf_package_get_evr(pkg), "3.1-0"));
+ pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ fail_if(strcmp(dnf_package_get_name(pkg), "flying"));
+ fail_if(strcmp(dnf_package_get_evr(pkg), "3.2-0"));
+
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+
+}
+END_TEST
+
+START_TEST(test_filter_latest_archs)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "penny-lib");
+ hy_query_filter_latest_per_arch(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 3); /* both architectures */
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_upgrade_already_installed)
+{
+ /* if pkg is installed in two versions and the later is available in repos,
+ it shouldn't show as a possible update. */
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ hy_query_filter_upgrades(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 0);
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_downgrade)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ hy_query_filter_downgrades(q, 1);
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ ck_assert_str_eq(dnf_package_get_evr(pkg), "4.9-0");
+ hy_query_free(q);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_downgradable)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter_downgradable(q, 1);
+ ck_assert_int_eq(query_count_results(q), 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_provides_str)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_PROVIDES, HY_EQ, "pilchard");
+ ck_assert_int_eq(query_count_results(q), 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_PROVIDES, HY_EQ, "fool = 1-2");
+ ck_assert_int_eq(query_count_results(q), 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_PROVIDES, HY_EQ, "thisisnotgoingtoexist");
+ ck_assert_int_eq(query_count_results(q), 0);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_provides_glob)
+ {
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_PROVIDES, HY_GLOB, "penny*");
+ ck_assert_int_eq(query_count_results(q), 6);
+ hy_query_free(q);
+
+ HyQuery q1 = hy_query_create(test_globals.sack);
+ HyQuery q2 = hy_query_create(test_globals.sack);
+ hy_query_filter(q1, HY_PKG_PROVIDES, HY_GLOB, "P-l*b >= 3");
+ hy_query_filter(q2, HY_PKG_PROVIDES, HY_EQ, "P-lib >= 3");
+ ck_assert_int_eq(query_count_results(q1), query_count_results(q2));
+ hy_query_free(q1);
+ hy_query_free(q2);
+
+ q1 = hy_query_create(test_globals.sack);
+ q2 = hy_query_create(test_globals.sack);
+ hy_query_filter(q1, HY_PKG_PROVIDES, HY_GLOB, "*");
+ fail_unless(query_count_results(q1) == query_count_results(q2));
+ hy_query_free(q1);
+ hy_query_free(q2);
+ }
+END_TEST
+
+START_TEST(test_query_rco_glob)
+ {
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_REQUIRES, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 5);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_REQUIRES, HY_GLOB, "*oo*");
+ ck_assert_int_eq(query_count_results(q), 2);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_CONFLICTS, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_OBSOLETES, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 0);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ENHANCES, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_RECOMMENDS, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SUGGESTS, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 1);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SUPPLEMENTS, HY_GLOB, "*");
+ ck_assert_int_eq(query_count_results(q), 1);
+ hy_query_free(q);
+ }
+END_TEST
+
+START_TEST(test_query_reldep)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *flying = by_name(sack, "flying");
+
+ DnfReldepList *reldeplist = dnf_package_get_requires(flying);
+ DnfReldep *reldep = dnf_reldep_list_index(reldeplist, 0);
+
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_if(hy_query_filter_reldep(q, HY_PKG_PROVIDES, reldep));
+ fail_unless(query_count_results(q) == 3);
+
+ delete reldep;
+ delete reldeplist;
+ g_object_unref(flying);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_reldep_arbitrary)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery query = hy_query_create(sack);
+ DnfReldep *reldep = dnf_reldep_new(sack, "P-lib", HY_GT, "3-0");
+
+ fail_if(reldep == NULL);
+ hy_query_filter_reldep(query, HY_PKG_PROVIDES, reldep);
+ fail_unless(query_count_results(query) == 3);
+
+ delete reldep;
+ hy_query_free(query);
+}
+END_TEST
+
+START_TEST(test_filter_files)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_FILE, HY_EQ, "/etc/takeyouaway");
+ GPtrArray *plist = hy_query_run(q);
+ fail_unless(plist->len == 1);
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ fail_if(strcmp(dnf_package_get_name(pkg), "tour"));
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_FILE, HY_GLOB, "/usr/*");
+ plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_sourcerpm)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_unless(hy_query_filter(q, HY_PKG_SOURCERPM, HY_GT, "tour-4-6.src.rpm"));
+ fail_if(hy_query_filter(q, HY_PKG_SOURCERPM, HY_EQ, "tour-4-6.src.rpm"));
+ fail_unless(size_and_free(q) == 1);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SOURCERPM, HY_EQ, "mystery-19.67-1.src.rpm");
+ fail_unless(size_and_free(q) == 1);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_SOURCERPM, HY_EQ,
+ "mystery-devel-19.67-1.noarch.rpm");
+ fail_unless(size_and_free(q) == 0);
+}
+END_TEST
+
+START_TEST(test_filter_description)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ fail_if(hy_query_filter(q, HY_PKG_DESCRIPTION, HY_SUBSTR,
+ "Magical development files for mystery."));
+ fail_unless(size_and_free(q) == 1);
+}
+END_TEST
+
+START_TEST(test_filter_obsoletes)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q = hy_query_create(sack);
+ DnfPackageSet *pset = dnf_packageset_new(sack); // empty
+
+ fail_if(hy_query_filter_package_in(q, HY_PKG_OBSOLETES, HY_EQ, pset));
+ fail_unless(query_count_results(q) == 0);
+ hy_query_clear(q);
+
+ DnfPackage *pkg = by_name(sack, "penny");
+ dnf_packageset_add(pset, pkg);
+ g_object_unref(pkg);
+ hy_query_filter_package_in(q, HY_PKG_OBSOLETES, HY_EQ, pset);
+ fail_unless(query_count_results(q) == 1);
+
+ hy_query_free(q);
+ delete pset;
+}
+END_TEST
+
+START_TEST(test_filter_reponames)
+{
+ HyQuery q;
+ const char *repolist[] = {"main", "updates", NULL};
+ const char *repolist2[] = {"main", NULL};
+ const char *repolist3[] = {"foo", "bar", NULL};
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter_in(q, HY_PKG_REPONAME, HY_EQ, repolist);
+ fail_unless(query_count_results(q) == TEST_EXPECT_MAIN_NSOLVABLES \
+ + TEST_EXPECT_UPDATES_NSOLVABLES);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter_in(q, HY_PKG_REPONAME, HY_EQ, repolist2);
+ fail_unless(query_count_results(q) == TEST_EXPECT_MAIN_NSOLVABLES);
+ hy_query_free(q);
+
+ q = hy_query_create(test_globals.sack);
+ hy_query_filter_in(q, HY_PKG_REPONAME, HY_EQ, repolist3);
+ fail_unless(query_count_results(q) == 0);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_excluded)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q = hy_query_create_flags(sack, HY_IGNORE_EXCLUDES);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+
+ DnfPackageSet *pset = hy_query_run_set(q);
+ dnf_sack_add_excludes(sack, pset);
+ delete pset;
+ hy_query_free(q);
+
+ q = hy_query_create_flags(sack, 0);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ fail_unless(query_count_results(q) == 0);
+ hy_query_free(q);
+
+ q = hy_query_create_flags(sack, HY_IGNORE_EXCLUDES);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ fail_unless(query_count_results(q) > 0);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_disabled_repo)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_EVR, HY_EQ, "4.9-0");
+ fail_unless(size_and_free(q) == 1);
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ ck_assert_int_eq(size_and_free(q), 5);
+
+ dnf_sack_repo_enabled(sack, "main", 0);
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_EVR, HY_EQ, "4.9-0");
+ fail_unless(size_and_free(q) == 0);
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "jay");
+ ck_assert_int_eq(size_and_free(q), 2);
+}
+END_TEST
+
+START_TEST(test_query_nevra_glob)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+ GPtrArray *plist;
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NEVRA, HY_GLOB, "p*4-1*");
+ plist = hy_query_run(q);
+
+ ck_assert_int_eq(plist->len, 2);
+ auto pkg1 = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ auto pkg2 = static_cast<DnfPackage *>(g_ptr_array_index(plist, 1));
+ const char *nevra1 = dnf_package_get_nevra(pkg1);
+ const char *nevra2 = dnf_package_get_nevra(pkg2);
+ ck_assert_str_eq(nevra1, "penny-4-1.noarch");
+ ck_assert_str_eq(nevra2, "penny-lib-4-1.x86_64");
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_nevra)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+ GPtrArray *plist;
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NEVRA, HY_EQ, "penny-4-1.noarch");
+ plist = hy_query_run(q);
+
+ ck_assert_int_eq(plist->len, 1);
+ auto pkg1 = static_cast<DnfPackage *>(g_ptr_array_index(plist, 0));
+ const char *nevra1 = dnf_package_get_nevra(pkg1);
+ ck_assert_str_eq(nevra1, "penny-4-1.noarch");
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_multiple_flags)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+ GPtrArray *plist;
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_NOT | HY_GLOB, "p*");
+ plist = hy_query_run(q);
+
+ ck_assert_int_eq(plist->len, 9);
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_query_apply)
+{
+ DnfSack *sack = test_globals.sack;
+ HyQuery q;
+ GPtrArray *plist;
+
+ q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_NOT | HY_GLOB, "j*");
+ struct libdnf::Query _q = *q;
+ fail_unless(_q.getResult() == NULL);
+ ck_assert_int_eq(_q.getApplied(), 0);
+ hy_query_apply(q);
+ _q = *q;
+ fail_unless(_q.getResult() != NULL);
+ ck_assert_int_eq(_q.getApplied(), 1);
+ hy_query_filter(q, HY_PKG_NAME, HY_NOT | HY_GLOB, "p*");
+ _q = *q;
+ fail_unless(_q.getResult() != NULL);
+ ck_assert_int_eq(_q.getApplied(), 0);
+ plist = hy_query_run(q);
+
+ ck_assert_int_eq(plist->len, 7);
+ g_ptr_array_unref(plist);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_advisory)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ADVISORY, HY_EQ, "BEATLES-1967-1127");
+ g_autoptr(GPtrArray) plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_advisory_type)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ADVISORY_TYPE, HY_EQ, "security");
+ g_autoptr(GPtrArray) plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_advisory_cve)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ADVISORY_CVE, HY_EQ, "CVE-1967-BEATLES");
+ g_autoptr(GPtrArray) plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_filter_advisory_bug)
+{
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_ADVISORY_BUG, HY_EQ, "0#john");
+ g_autoptr(GPtrArray) plist = hy_query_run(q);
+ fail_unless(plist->len == 2);
+ hy_query_free(q);
+}
+END_TEST
+
+START_TEST(test_difference)
+{
+ HyQuery q1 = hy_query_create(test_globals.sack);
+ hy_query_filter(q1, HY_PKG_VERSION, HY_EQ, "4");
+ HyQuery q2 = hy_query_create(test_globals.sack);
+ hy_query_filter(q2, HY_PKG_NAME, HY_GLOB, "p*");
+
+ hy_query_difference(q1, q2);
+ GPtrArray *plist = hy_query_run(q1);
+ fail_unless(plist->len == 2);
+ hy_query_free(q2);
+ hy_query_free(q1);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_intersection)
+{
+ HyQuery q1 = hy_query_create(test_globals.sack);
+ hy_query_filter(q1, HY_PKG_VERSION, HY_EQ, "4");
+ HyQuery q2 = hy_query_create(test_globals.sack);
+ hy_query_filter(q2, HY_PKG_NAME, HY_GLOB, "p*");
+
+ hy_query_intersection(q1, q2);
+ GPtrArray *plist = hy_query_run(q1);
+ fail_unless(plist->len == 7);
+ hy_query_free(q2);
+ hy_query_free(q1);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+START_TEST(test_union)
+{
+ HyQuery q1 = hy_query_create(test_globals.sack);
+ hy_query_filter(q1, HY_PKG_VERSION, HY_EQ, "4");
+ HyQuery q2 = hy_query_create(test_globals.sack);
+ hy_query_filter(q2, HY_PKG_NAME, HY_GLOB, "p*");
+
+ hy_query_union(q1, q2);
+ GPtrArray *plist = hy_query_run(q1);
+ fail_unless(plist->len == 11);
+ hy_query_free(q2);
+ hy_query_free(q1);
+ g_ptr_array_unref(plist);
+}
+END_TEST
+
+Suite *
+query_suite(void)
+{
+ Suite *s = suite_create("Query");
+ TCase *tc;
+
+ tc = tcase_create("Core");
+ tcase_add_unchecked_fixture(tc, fixture_system_only, teardown);
+ tcase_add_test(tc, test_query_sanity);
+ tcase_add_test(tc, test_query_run_set_sanity);
+ tcase_add_test(tc, test_query_clear);
+ tcase_add_test(tc, test_query_clone);
+ tcase_add_test(tc, test_query_empty);
+ tcase_add_test(tc, test_query_repo);
+ tcase_add_test(tc, test_query_installed_available);
+ tcase_add_test(tc, test_query_name);
+ tcase_add_test(tc, test_query_evr);
+ tcase_add_test(tc, test_query_epoch);
+ tcase_add_test(tc, test_query_version);
+ tcase_add_test(tc, test_query_release);
+ tcase_add_test(tc, test_query_glob);
+ tcase_add_test(tc, test_query_case);
+ tcase_add_test(tc, test_query_anded);
+ tcase_add_test(tc, test_query_neq);
+ tcase_add_test(tc, test_query_in);
+ tcase_add_test(tc, test_query_pkg);
+ tcase_add_test(tc, test_query_provides);
+ tcase_add_test(tc, test_query_fileprovides);
+ tcase_add_test(tc, test_query_nevra);
+ tcase_add_test(tc, test_query_nevra_glob);
+ tcase_add_test(tc, test_query_multiple_flags);
+ tcase_add_test(tc, test_query_apply);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Updates");
+ tcase_add_unchecked_fixture(tc, fixture_with_updates, teardown);
+ tcase_add_test(tc, test_upgrades_sanity);
+ tcase_add_test(tc, test_upgrades);
+ tcase_add_test(tc, test_upgradable);
+ tcase_add_test(tc, test_filter_latest);
+ tcase_add_test(tc, test_query_provides_in);
+ tcase_add_test(tc, test_query_provides_in_not_found);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Main");
+ tcase_add_unchecked_fixture(tc, fixture_with_main, teardown);
+ tcase_add_test(tc, test_upgrade_already_installed);
+ tcase_add_test(tc, test_downgrade);
+ tcase_add_test(tc, test_downgradable);
+ tcase_add_test(tc, test_query_provides_str);
+ tcase_add_test(tc, test_query_provides_glob);
+ tcase_add_test(tc, test_query_rco_glob);
+ tcase_add_test(tc, test_query_recommends);
+ tcase_add_test(tc, test_query_suggests);
+ tcase_add_test(tc, test_query_supplements);
+ tcase_add_test(tc, test_query_enhances);
+ tcase_add_test(tc, test_query_reldep);
+ tcase_add_test(tc, test_query_reldep_arbitrary);
+ tcase_add_test(tc, test_query_conflicts);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Full");
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ tcase_add_test(tc, test_filter_latest2);
+ tcase_add_test(tc, test_filter_latest_archs);
+ tcase_add_test(tc, test_filter_obsoletes);
+ tcase_add_test(tc, test_filter_reponames);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Filelists etc.");
+ tcase_add_unchecked_fixture(tc, fixture_yum, teardown);
+ tcase_add_test(tc, test_filter_files);
+ tcase_add_test(tc, test_filter_sourcerpm);
+ tcase_add_test(tc, test_filter_description);
+ tcase_add_test(tc, test_query_location);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Excluding");
+ tcase_add_unchecked_fixture(tc, fixture_with_main, teardown);
+ tcase_add_checked_fixture(tc, fixture_reset, NULL);
+ tcase_add_test(tc, test_excluded);
+ tcase_add_test(tc, test_disabled_repo);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Advisories");
+ tcase_add_unchecked_fixture(tc, fixture_yum, teardown);
+ tcase_add_test(tc, test_filter_advisory);
+ tcase_add_test(tc, test_filter_advisory_type);
+ tcase_add_test(tc, test_filter_advisory_cve);
+ tcase_add_test(tc, test_filter_advisory_bug);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Set Operations");
+ tcase_add_unchecked_fixture(tc, fixture_with_main, teardown);
+ tcase_add_test(tc, test_difference);
+ tcase_add_test(tc, test_intersection);
+ tcase_add_test(tc, test_union);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/hy-package.h"
+#include "libdnf/dnf-reldep.h"
+#include "libdnf/dnf-reldep-list.h"
+#include "libdnf/dnf-sack.h"
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+#include "libdnf/repo/solvable/Dependency.hpp"
+
+#include <memory>
+
+#include "fixtures.h"
+#include "test_suites.h"
+#include "testsys.h"
+
+START_TEST(test_reldeplist_add)
+{
+ DnfSack *sack = test_globals.sack;
+ DnfPackage *flying = by_name_repo(sack, "fool", "updates");
+ std::unique_ptr<DnfReldepList> reldeplist(dnf_reldep_list_new (sack));
+ std::unique_ptr<DnfReldepList> obsoletes(dnf_package_get_obsoletes (flying));
+
+ const int count = dnf_reldep_list_count (obsoletes.get());
+ fail_unless(count == 2);
+ for (int i = 0; i < count; ++i) {
+ DnfReldep *reldep = dnf_reldep_list_index (obsoletes.get(), i);
+ dnf_reldep_list_add (reldeplist.get(), reldep);
+ delete reldep;
+ }
+
+ g_object_unref (flying);
+ fail_unless(dnf_reldep_list_count (reldeplist.get()) == 2);
+}
+END_TEST
+
+Suite *
+reldep_suite(void)
+{
+ Suite *s = suite_create("Reldep");
+ TCase *tc = tcase_create("Core");
+ tcase_add_unchecked_fixture(tc, fixture_with_updates, teardown);
+ tcase_add_test(tc, test_reldeplist_add);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/hy-iutil-private.hpp"
+#include "libdnf/hy-repo-private.hpp"
+#include "libdnf/repo/Repo-private.hpp"
+
+#include "fixtures.h"
+#include "testshared.h"
+#include "test_suites.h"
+
+#include <check.h>
+#include <string.h>
+
+START_TEST(test_strings)
+{
+ HyRepo hrepo = hy_repo_create("happy2");
+ ck_assert_str_eq(hy_repo_get_string(hrepo, HY_REPO_NAME), "happy2");
+ hy_repo_set_string(hrepo, HY_REPO_PRESTO_FN, "tunedtoA");
+ ck_assert_str_eq(hy_repo_get_string(hrepo, HY_REPO_PRESTO_FN), "tunedtoA");
+ hy_repo_set_string(hrepo, HY_REPO_PRESTO_FN, "naturalE");
+ ck_assert_str_eq(hy_repo_get_string(hrepo, HY_REPO_PRESTO_FN), "naturalE");
+ hy_repo_free(hrepo);
+}
+END_TEST
+
+START_TEST(test_cost)
+{
+ DnfSack *sack = test_globals.sack;
+ HyRepo repo = hrepo_by_name(sack, YUM_REPO_NAME);
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ hy_repo_set_cost(repo, 700);
+ fail_unless(repoImpl->libsolvRepo != NULL);
+ fail_unless(700 == hy_repo_get_cost(repo));
+ int subpriority = -700;
+ fail_unless(repoImpl->libsolvRepo->subpriority == subpriority);
+}
+END_TEST
+
+Suite *
+repo_suite(void)
+{
+ Suite *s = suite_create("Repo");
+ TCase *tc = tcase_create("Core");
+ tcase_add_test(tc, test_strings);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Cost");
+ tcase_add_unchecked_fixture(tc, fixture_yum, teardown);
+ tcase_add_test(tc, test_cost);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2015 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <libdnf/repo/Repo-private.hpp>
+#include "libdnf/dnf-types.h"
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-repo-private.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-util.h"
+#include "libdnf/hy-iutil-private.hpp"
+
+#include "fixtures.h"
+#include "testsys.h"
+#include "test_suites.h"
+
+#include <solv/testcase.h>
+
+#include <glib/gstdio.h>
+
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+START_TEST(test_environment)
+{
+ /* check the tmpdir was created */
+ fail_if(access(test_globals.tmpdir, W_OK));
+}
+END_TEST
+
+START_TEST(test_sack_create)
+{
+ g_autoptr(DnfSack) sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ fail_if(sack == NULL, NULL);
+ fail_if(dnf_sack_get_pool(sack) == NULL, NULL);
+}
+END_TEST
+
+START_TEST(test_give_cache_fn)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+
+ char *path = dnf_sack_give_cache_fn(sack, "rain", NULL);
+ fail_if(strstr(path, "rain.solv") == NULL);
+ g_free(path);
+
+ path = dnf_sack_give_cache_fn(sack, "rain", HY_EXT_FILENAMES);
+ fail_if(strstr(path, "rain-filenames.solvx") == NULL);
+ g_free(path);
+ g_object_unref(sack);
+}
+END_TEST
+
+START_TEST(test_list_arches)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ dnf_sack_set_arch(sack, TEST_FIXED_ARCH, NULL);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ const char ** arches = dnf_sack_list_arches(sack);
+
+ /* noarch, x86_64, athlon, i686, i586, i486, i386 */
+ fail_unless(g_strv_length((gchar**)arches) >= 6 && g_strv_length((gchar**)arches) <= 7);
+
+ if (g_strv_length((gchar**)arches) == 7) {
+ // Fedora, Mageia
+ ck_assert_str_eq(arches[0], "noarch");
+ ck_assert_str_eq(arches[1], "x86_64");
+ ck_assert_str_eq(arches[2], "athlon");
+ ck_assert_str_eq(arches[3], "i686");
+ ck_assert_str_eq(arches[4], "i586");
+ ck_assert_str_eq(arches[5], "i486");
+ ck_assert_str_eq(arches[6], "i386");
+ } else {
+ // openSUSE, Debian - "athlon" is not available
+ ck_assert_str_eq(arches[0], "noarch");
+ ck_assert_str_eq(arches[1], "x86_64");
+ ck_assert_str_eq(arches[2], "i686");
+ ck_assert_str_eq(arches[3], "i586");
+ ck_assert_str_eq(arches[4], "i486");
+ ck_assert_str_eq(arches[5], "i386");
+ }
+
+ g_free(arches);
+ g_object_unref(sack);
+}
+END_TEST
+
+START_TEST(test_load_repo_err)
+{
+ g_autoptr(GError) error = NULL;
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, &error));
+ g_assert(sack != NULL);
+ HyRepo repo = hy_repo_create("crabalocker");
+ g_assert(repo != NULL);
+ hy_repo_set_string(repo, HY_REPO_MD_FN, "/non/existing");
+ fail_unless(!dnf_sack_load_repo(sack, repo, 0, &error));
+ fail_unless(g_error_matches (error, DNF_ERROR, DNF_ERROR_FILE_INVALID));
+ hy_repo_free(repo);
+ g_object_unref(sack);
+}
+END_TEST
+
+START_TEST(test_repo_written)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ char *filename = dnf_sack_give_cache_fn(sack, "test_sack_written", NULL);
+
+ fail_unless(access(filename, R_OK|W_OK));
+ setup_yum_sack(sack, "test_sack_written");
+
+ HyRepo repo = hrepo_by_name(sack, "test_sack_written");
+ auto repoImpl = libdnf::repoGetImpl(repo);
+ fail_if(repo == NULL);
+ fail_unless(repoImpl->state_main == _HY_WRITTEN);
+ fail_unless(repoImpl->state_filelists == _HY_WRITTEN);
+ fail_unless(repoImpl->state_presto == _HY_WRITTEN);
+ fail_if(access(filename, R_OK|W_OK));
+
+ g_free(filename);
+ g_object_unref(sack);
+}
+END_TEST
+
+START_TEST(test_add_cmdline_package)
+{
+ g_autoptr(DnfSack) sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+
+ g_autofree gchar *path_mystery = g_build_filename (TESTDATADIR, "/hawkey/yum/mystery-devel-19.67-1.noarch.rpm", NULL);
+ g_autoptr(DnfPackage) pkg_mystery = dnf_sack_add_cmdline_package (sack, path_mystery);
+ const gchar *location_mystery = dnf_package_get_location(pkg_mystery);
+ ck_assert_str_eq(path_mystery, location_mystery);
+
+ g_autofree gchar *path_tour = g_build_filename (TESTDATADIR, "/hawkey/yum/tour-4-6.noarch.rpm", NULL);
+ g_autoptr(DnfPackage) pkg_tour = dnf_sack_add_cmdline_package (sack, path_tour);
+ const gchar *location_tour = dnf_package_get_location(pkg_tour);
+ ck_assert_str_eq(path_tour, location_tour);
+
+ g_autofree gchar *path_null_rpm = g_build_filename (test_globals.tmpdir, "null.rpm", NULL);
+ FILE *fp = g_fopen (path_null_rpm, "w");
+ fail_unless (fp != NULL);
+ fclose (fp);
+ fail_unless (dnf_sack_add_cmdline_package (sack, path_null_rpm) == NULL);
+}
+END_TEST
+
+START_TEST(test_repo_load)
+{
+ fail_unless(dnf_sack_count(test_globals.sack) ==
+ TEST_EXPECT_SYSTEM_NSOLVABLES);
+}
+END_TEST
+
+static void
+check_filelist(Pool *pool)
+{
+ Dataiterator di;
+ int count;
+ Id last_found_solvable = 0;
+ dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, "/usr/bin/ste",
+ SEARCH_STRING | SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
+ for (count = 0; dataiterator_step(&di); ++count)
+ last_found_solvable = di.solvid;
+ fail_unless(count == 1);
+ fail_if(last_found_solvable == 0);
+ dataiterator_free(&di);
+
+ dataiterator_init(&di, pool, 0, last_found_solvable, SOLVABLE_FILELIST, "/",
+ SEARCH_STRINGSTART | SEARCH_FILES);
+ for (count = 0; dataiterator_step(&di); ++count)
+ fail_if(strncmp(di.kv.str, "/usr/bin/", strlen("/usr/bin/")));
+ fail_unless(count == 3);
+ dataiterator_free(&di);
+
+ dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST,
+ "/usr/lib/python2.7/site-packages/tour/today.pyc",
+ SEARCH_STRING | SEARCH_FILES | SEARCH_COMPLETE_FILELIST);
+ for (count = 0; dataiterator_step(&di); ++count) ;
+ fail_unless(count == 1);
+ dataiterator_free(&di);
+}
+
+START_TEST(test_filelist)
+{
+ DnfSack *sack = test_globals.sack;
+ HyRepo repo = hrepo_by_name(sack, YUM_REPO_NAME);
+ char *fn_solv = dnf_sack_give_cache_fn(sack, YUM_REPO_NAME, HY_EXT_FILENAMES);
+
+ fail_unless(libdnf::repoGetImpl(repo)->state_filelists == _HY_WRITTEN);
+ fail_if(access(fn_solv, R_OK));
+ g_free(fn_solv);
+
+ check_filelist(dnf_sack_get_pool(test_globals.sack));
+}
+END_TEST
+
+START_TEST(test_filelist_from_cache)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ setup_yum_sack(sack, YUM_REPO_NAME);
+
+ HyRepo repo = hrepo_by_name(sack, YUM_REPO_NAME);
+ fail_unless(libdnf::repoGetImpl(repo)->state_filelists == _HY_LOADED_CACHE);
+ check_filelist(dnf_sack_get_pool(sack));
+ g_object_unref(sack);
+}
+END_TEST
+
+static void
+check_prestoinfo(Pool *pool)
+{
+ Dataiterator di;
+
+ dataiterator_init(&di, pool, NULL, SOLVID_META, DELTA_PACKAGE_NAME, "tour",
+ SEARCH_STRING);
+ dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO);
+ fail_unless(dataiterator_step(&di));
+ dataiterator_setpos_parent(&di);
+ const char *attr;
+ attr = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME);
+ ck_assert_str_eq(attr, "tour");
+ attr = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR);
+ ck_assert_str_eq(attr, "4-5");
+ attr = pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_DIR);
+ ck_assert_str_eq(attr, "drpms");
+ dataiterator_free(&di);
+ return;
+}
+
+START_TEST(test_presto)
+{
+ DnfSack *sack = test_globals.sack;
+ HyRepo repo = hrepo_by_name(sack, YUM_REPO_NAME);
+ char *fn_solv = dnf_sack_give_cache_fn(sack, YUM_REPO_NAME, HY_EXT_PRESTO);
+
+ fail_if(access(fn_solv, R_OK));
+ fail_unless(libdnf::repoGetImpl(repo)->state_presto == _HY_WRITTEN);
+ g_free(fn_solv);
+ check_prestoinfo(dnf_sack_get_pool(sack));
+}
+END_TEST
+
+START_TEST(test_presto_from_cache)
+{
+ DnfSack *sack = dnf_sack_new();
+ dnf_sack_set_cachedir(sack, test_globals.tmpdir);
+ dnf_sack_set_arch(sack, TEST_FIXED_ARCH, NULL);
+ fail_unless(dnf_sack_setup(sack, DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR, NULL));
+ setup_yum_sack(sack, YUM_REPO_NAME);
+
+ HyRepo repo = hrepo_by_name(sack, YUM_REPO_NAME);
+ fail_unless(libdnf::repoGetImpl(repo)->state_presto == _HY_LOADED_CACHE);
+ check_prestoinfo(dnf_sack_get_pool(sack));
+ g_object_unref(sack);
+}
+END_TEST
+
+Suite *
+sack_suite(void)
+{
+ Suite *s = suite_create("Sack");
+ TCase *tc = tcase_create("Core");
+ tcase_add_test(tc, test_environment);
+ tcase_add_test(tc, test_sack_create);
+ tcase_add_test(tc, test_give_cache_fn);
+ tcase_add_test(tc, test_list_arches);
+ tcase_add_test(tc, test_load_repo_err);
+ tcase_add_test(tc, test_repo_written);
+ tcase_add_test(tc, test_add_cmdline_package);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Repos");
+ tcase_add_unchecked_fixture(tc, fixture_system_only, teardown);
+ tcase_add_test(tc, test_repo_load);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("YumRepo");
+ tcase_add_unchecked_fixture(tc, fixture_yum, teardown);
+ tcase_add_test(tc, test_filelist);
+ tcase_add_test(tc, test_filelist_from_cache);
+ tcase_add_test(tc, test_presto);
+ tcase_add_test(tc, test_presto_from_cache);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("SackKnows");
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-query.h"
+#include "libdnf/hy-selector.h"
+#include "libdnf/dnf-types.h"
+#include "libdnf/hy-util-private.hpp"
+#include "libdnf/sack/packageset.hpp"
+#include "fixtures.h"
+#include "testsys.h"
+#include "test_suites.h"
+
+START_TEST(test_sltr_pkg)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ DnfPackageSet *pset = dnf_packageset_new(test_globals.sack);
+
+ HyQuery q = hy_query_create(test_globals.sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, "penny");
+ GPtrArray *plist1 = hy_query_run(q);
+ hy_query_free(q);
+ fail_unless(plist1->len == 2);
+ auto pkg0 = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist1, 0)));
+ auto pkg1 = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist1, 1)));
+ g_ptr_array_unref(plist1);
+ dnf_packageset_add(pset, pkg0);
+
+ fail_if(hy_selector_pkg_set(sltr, pset));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 1);
+ fail_unless(hy_packagelist_has(plist, pkg0));
+ fail_if(hy_packagelist_has(plist, pkg1));
+
+ g_object_unref(pkg0);
+ g_object_unref(pkg1);
+ delete pset;
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_matching)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "penny"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 2);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_provides)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ fail_if(hy_selector_set(sltr, HY_PKG_PROVIDES, HY_EQ, "*"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 0);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_provides_glob)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+ fail_if(hy_selector_set(sltr, HY_PKG_PROVIDES, HY_GLOB, "*alru*"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 2);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_reponame)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "penny"));
+ fail_if(hy_selector_set(sltr, HY_PKG_REPONAME, HY_EQ, "main"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 1);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_reponame_nonexistent)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_GLOB, "*"));
+ fail_if(hy_selector_set(sltr, HY_PKG_REPONAME, HY_EQ, "non-existent"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 0);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+START_TEST(test_sltr_version)
+{
+ HySelector sltr = hy_selector_create(test_globals.sack);
+
+ fail_if(hy_selector_set(sltr, HY_PKG_NAME, HY_EQ, "jay"));
+ fail_if(hy_selector_set(sltr, HY_PKG_VERSION, HY_EQ, "5.0"));
+ GPtrArray *plist = hy_selector_matches(sltr);
+ fail_unless(plist->len == 2);
+
+ g_ptr_array_unref(plist);
+ hy_selector_free(sltr);
+}
+END_TEST
+
+Suite *
+selector_suite(void)
+{
+ Suite *s = suite_create("Selector");
+ TCase *tc = tcase_create("Core");
+
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ tcase_add_test(tc, test_sltr_pkg);
+ tcase_add_test(tc, test_sltr_matching);
+ tcase_add_test(tc, test_sltr_provides);
+ tcase_add_test(tc, test_sltr_provides_glob);
+ tcase_add_test(tc, test_sltr_reponame);
+ tcase_add_test(tc, test_sltr_reponame_nonexistent);
+ tcase_add_test(tc, test_sltr_version);
+
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/nevra.hpp"
+#include "libdnf/nsvcap.hpp"
+#include "libdnf/dnf-reldep.h"
+#include "libdnf/dnf-sack.h"
+#include "libdnf/hy-subject.h"
+
+#include "fixtures.h"
+#include "testshared.h"
+#include "test_suites.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <check.h>
+#include <string.h>
+
+const char inp_fof[] = "four-of-fish-8:3.6.9-11.fc100.x86_64";
+const char inp_fof_noepoch[] = "four-of-fish-3.6.9-11.fc100.x86_64";
+const char inp_fof_nev[] = "four-of-fish-8:3.6.9";
+const char inp_fof_na[] = "four-of-fish-3.6.9.i686";
+
+/* module_forms */
+/* with profile */
+const char module_nsvcap[] = "module-name:stream:1:b86c854:x86_64/profile";
+const char module_nsvap[] = "module-name:stream:1::x86_64/profile";
+const char module_nsvp[] = "module-name:stream:1/profile";
+const char module_nsap[] = "module-name:stream::x86_64/profile";
+const char module_nsp[] = "module-name:stream/profile";
+const char module_np[] = "module-name/profile";
+const char module_nap[] = "module-name::x86_64/profile";
+
+/* without profile */
+const char module_nsvca[] = "module-name:stream:1:b86c854:x86_64";
+const char module_nsva[] = "module-name:stream:1::x86_64";
+const char module_nsvc[] = "module-name:stream:1:b86c854";
+const char module_nsvc2[] = "module-name:stream:1:muj-cont_ext.5";
+const char module_nsv[] = "module-name:stream:1";
+const char module_nsa[] = "module-name:stream::x86_64";
+const char module_ns[] = "module-name:stream";
+const char module_n[] = "module-name";
+const char module_na[] = "module-name::x86_64";
+
+START_TEST(nevra1)
+{
+ libdnf::Nevra nevra;
+ ck_assert(nevra.parse(inp_fof, HY_FORM_NEVRA));
+ ck_assert_str_eq(nevra.getName().c_str(), "four-of-fish");
+ ck_assert_int_eq(nevra.getEpoch(), 8);
+ ck_assert_str_eq(nevra.getVersion().c_str(), "3.6.9");
+ ck_assert_str_eq(nevra.getRelease().c_str(), "11.fc100");
+ ck_assert_str_eq(nevra.getArch().c_str(), "x86_64");
+
+ // NEVRA comparison tests
+ libdnf::Nevra nevra2;
+ nevra2.setEpoch(8);
+ nevra2.setName("four-of-fish");
+ nevra2.setVersion("3.6.9");
+ nevra2.setRelease("11.fc100");
+ nevra2.setArch("x86_64");
+ ck_assert_int_eq(nevra.compare(nevra2), 0);
+
+ nevra2.setEpoch(3);
+ ck_assert_int_gt(nevra.compare(nevra2), 0);
+
+ nevra2.setEpoch(11);
+ ck_assert_int_lt(nevra.compare(nevra2), 0);
+
+ nevra2.setEpoch(8);
+ nevra2.setVersion("7.0");
+ ck_assert_int_lt(nevra.compare(nevra2), 0);
+
+ nevra2.setEpoch(8);
+ nevra2.setVersion("");
+ ck_assert_int_gt(nevra.compare(nevra2), 0);
+
+ nevra2.setEpoch(8);
+ nevra.setVersion("");
+ ck_assert_int_eq(nevra.compare(nevra2), 0);
+}
+END_TEST
+
+
+START_TEST(nevra2)
+{
+ libdnf::Nevra nevra;
+ ck_assert(nevra.parse(inp_fof_noepoch, HY_FORM_NEVRA));
+ ck_assert_str_eq(nevra.getName().c_str(), "four-of-fish");
+ ck_assert_int_eq(nevra.getEpoch(), libdnf::Nevra::EPOCH_NOT_SET);
+ ck_assert_str_eq(nevra.getVersion().c_str(), "3.6.9");
+ ck_assert_str_eq(nevra.getRelease().c_str(), "11.fc100");
+ ck_assert_str_eq(nevra.getArch().c_str(), "x86_64");
+}
+END_TEST
+
+START_TEST(nevr)
+{
+ libdnf::Nevra nevra;
+ ck_assert(nevra.parse(inp_fof, HY_FORM_NEVR));
+ ck_assert_str_eq(nevra.getName().c_str(), "four-of-fish");
+ ck_assert_int_eq(nevra.getEpoch(), 8);
+ ck_assert_str_eq(nevra.getVersion().c_str(), "3.6.9");
+ ck_assert_str_eq(nevra.getRelease().c_str(), "11.fc100.x86_64");
+ fail_unless(nevra.getArch().empty());
+}
+END_TEST
+
+START_TEST(nevr_fail)
+{
+ libdnf::Nevra nevra;
+ ck_assert(!nevra.parse("four-of", HY_FORM_NEVR));
+}
+END_TEST
+
+START_TEST(nev)
+{
+ libdnf::Nevra nevra;
+ ck_assert(nevra.parse(inp_fof_nev, HY_FORM_NEV));
+ ck_assert_str_eq(nevra.getName().c_str(), "four-of-fish");
+ ck_assert_int_eq(nevra.getEpoch(), 8);
+ ck_assert_str_eq(nevra.getVersion().c_str(), "3.6.9");
+ fail_unless(nevra.getRelease().empty());
+ fail_unless(nevra.getArch().empty());
+}
+END_TEST
+
+START_TEST(na)
+{
+ libdnf::Nevra nevra;
+ ck_assert(nevra.parse(inp_fof_na, HY_FORM_NA));
+ ck_assert_str_eq(nevra.getName().c_str(), "four-of-fish-3.6.9");
+ ck_assert_int_eq(nevra.getEpoch(), libdnf::Nevra::EPOCH_NOT_SET);
+ fail_unless(nevra.getVersion().empty());
+ ck_assert_str_eq(nevra.getArch().c_str(), "i686");
+}
+END_TEST
+
+START_TEST(module_form_nsvcap)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvcap, HY_MODULE_FORM_NSVCAP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getContext().c_str(), "b86c854");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_nsvap)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvap, HY_MODULE_FORM_NSVAP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_nsvca)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvca, HY_MODULE_FORM_NSVCA));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getContext().c_str(), "b86c854");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+}
+END_TEST
+
+START_TEST(module_form_nsva)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsva, HY_MODULE_FORM_NSVA));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+}
+END_TEST
+
+START_TEST(module_form_nsvp)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvp, HY_MODULE_FORM_NSVP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_nsvc)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvc, HY_MODULE_FORM_NSVC));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getContext().c_str(), "b86c854");
+}
+END_TEST
+
+START_TEST(module_form_nsvc2)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsvc2, HY_MODULE_FORM_NSVC));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+ ck_assert_str_eq(nsvcap.getContext().c_str(), "muj-cont_ext.5");
+}
+END_TEST
+
+START_TEST(module_form_nsv)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsv, HY_MODULE_FORM_NSV));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getVersion().c_str(), "1");
+}
+END_TEST
+
+START_TEST(module_form_nsap)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsap, HY_MODULE_FORM_NSAP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_nsa)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsa, HY_MODULE_FORM_NSA));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+}
+END_TEST
+
+START_TEST(module_form_nsp)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nsp, HY_MODULE_FORM_NSP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_ns)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_ns, HY_MODULE_FORM_NS));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getStream().c_str(), "stream");
+}
+END_TEST
+
+START_TEST(module_form_nap)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_nap, HY_MODULE_FORM_NAP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_na)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_na, HY_MODULE_FORM_NA));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getArch().c_str(), "x86_64");
+}
+END_TEST
+
+START_TEST(module_form_np)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_np, HY_MODULE_FORM_NP));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+ ck_assert_str_eq(nsvcap.getProfile().c_str(), "profile");
+}
+END_TEST
+
+START_TEST(module_form_n)
+{
+ libdnf::Nsvcap nsvcap;
+ ck_assert(nsvcap.parse(module_n, HY_MODULE_FORM_N));
+ ck_assert_str_eq(nsvcap.getName().c_str(), "module-name");
+}
+END_TEST
+
+Suite *
+subject_suite(void)
+{
+ Suite *s = suite_create("Subject");
+ TCase *tc = tcase_create("Core");
+ tcase_add_test(tc, nevra1);
+ tcase_add_test(tc, nevra2);
+ tcase_add_test(tc, nevr);
+ tcase_add_test(tc, nevr_fail);
+ tcase_add_test(tc, nev);
+ tcase_add_test(tc, na);
+ tcase_add_test(tc, module_form_nsvcap);
+ tcase_add_test(tc, module_form_nsvap);
+ tcase_add_test(tc, module_form_nsvca);
+ tcase_add_test(tc, module_form_nsva);
+ tcase_add_test(tc, module_form_nsvp);
+ tcase_add_test(tc, module_form_nsvc);
+ tcase_add_test(tc, module_form_nsvc2);
+ tcase_add_test(tc, module_form_nsv);
+ tcase_add_test(tc, module_form_nsap);
+ tcase_add_test(tc, module_form_nsa);
+ tcase_add_test(tc, module_form_nsp);
+ tcase_add_test(tc, module_form_ns);
+ tcase_add_test(tc, module_form_nap);
+ tcase_add_test(tc, module_form_na);
+ tcase_add_test(tc, module_form_np);
+ tcase_add_test(tc, module_form_n);
+ suite_add_tcase(s, tc);
+
+ tc = tcase_create("Full");
+ tcase_add_unchecked_fixture(tc, fixture_all, teardown);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2014 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_SUITES_H
+#define TEST_SUITES_H
+
+#include <check.h>
+
+Suite *advisory_suite(void);
+Suite *advisorypkg_suite(void);
+Suite *advisoryref_suite(void);
+Suite *goal_suite(void);
+Suite *iutil_suite(void);
+Suite *package_suite(void);
+Suite *packagelist_suite(void);
+Suite *packageset_suite(void);
+Suite *query_suite(void);
+Suite *reldep_suite(void);
+Suite *repo_suite(void);
+Suite *sack_suite(void);
+Suite *selector_suite(void);
+Suite *subject_suite(void);
+Suite *util_suite(void);
+
+#endif // TEST_SUITES_H
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/dnf-types.h"
+#include "libdnf/hy-util.h"
+
+#include "test_suites.h"
+
+#include <check.h>
+#include <stdio.h>
+
+START_TEST(test_detect_arch)
+{
+ char *arch;
+ int ret = hy_detect_arch(&arch);
+ int len = strlen(arch);
+ ck_assert_int_gt(len, 0);
+ ck_assert_int_eq(ret, 0);
+ g_free(arch);
+}
+END_TEST
+
+START_TEST(test_split_nevra)
+{
+ int ret;
+ int epoch;
+ char *name, *version, *release, *arch;
+
+ const char *n = "meanwhile3.34.3-3:3.34-3.fc666.i686";
+ fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
+ ck_assert_str_eq(name, "meanwhile3.34.3");
+ fail_unless(epoch == 3);
+ ck_assert_str_eq(version, "3.34");
+ ck_assert_str_eq(release, "3.fc666");
+ ck_assert_str_eq(arch, "i686");
+ g_free(name);
+ g_free(version);
+ g_free(release);
+ g_free(arch);
+
+ n = "python-meanwhile3.34.3-3:3.34-3.fc666.noarch";
+ fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
+ ck_assert_str_eq(name, "python-meanwhile3.34.3");
+ fail_unless(epoch == 3);
+ ck_assert_str_eq(version, "3.34");
+ ck_assert_str_eq(release, "3.fc666");
+ ck_assert_str_eq(arch, "noarch");
+ g_free(name);
+ g_free(version);
+ g_free(release);
+ g_free(arch);
+
+ n = "easy-1.2.3-4.fc18.x86_64";
+ fail_if(hy_split_nevra(n, &name, &epoch, &version, &release, &arch));
+ ck_assert_str_eq(name, "easy");
+ fail_unless(epoch == 0);
+ ck_assert_str_eq(version, "1.2.3");
+ ck_assert_str_eq(release, "4.fc18");
+ ck_assert_str_eq(arch, "x86_64");
+ g_free(name);
+ g_free(version);
+ g_free(release);
+ g_free(arch);
+
+ n = "no.go";
+ ret = hy_split_nevra(n, &name, &epoch, &version, &release, &arch);
+ fail_unless(ret == DNF_ERROR_INTERNAL_ERROR);
+}
+END_TEST
+
+Suite *
+util_suite(void)
+{
+ Suite *s = suite_create("util");
+ TCase *tc = tcase_create("Main");
+ tcase_add_test(tc, test_detect_arch);
+ tcase_add_test(tc, test_split_nevra);
+ suite_add_tcase(s, tc);
+
+ return s;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/hy-repo.h"
+#include "libdnf/hy-repo-private.hpp"
+#include "libdnf/repo/Repo-private.hpp"
+
+#include "testshared.h"
+
+extern "C" {
+#include <solv/pool.h>
+#include <solv/repo.h>
+#include <solv/testcase.h>
+}
+
+#include <wordexp.h>
+
+HyRepo
+glob_for_repofiles(Pool *pool, const char *repo_name, const char *path)
+{
+ HyRepo repo = hy_repo_create(repo_name);
+ const char *tmpl;
+ wordexp_t word_vector;
+
+ tmpl = pool_tmpjoin(pool, path, "/repomd.xml", NULL);
+ if (wordexp(tmpl, &word_vector, 0) || word_vector.we_wordc < 1)
+ goto fail;
+ hy_repo_set_string(repo, HY_REPO_MD_FN, word_vector.we_wordv[0]);
+
+ tmpl = pool_tmpjoin(pool, path, "/*primary.xml.gz", NULL);
+ if (wordexp(tmpl, &word_vector, WRDE_REUSE) || word_vector.we_wordc < 1)
+ goto fail;
+ hy_repo_set_string(repo, HY_REPO_PRIMARY_FN, word_vector.we_wordv[0]);
+
+ tmpl = pool_tmpjoin(pool, path, "/*filelists.xml.gz", NULL);
+ if (wordexp(tmpl, &word_vector, WRDE_REUSE) || word_vector.we_wordc < 1)
+ goto fail;
+ hy_repo_set_string(repo, HY_REPO_FILELISTS_FN, word_vector.we_wordv[0]);
+
+ tmpl = pool_tmpjoin(pool, path, "/*prestodelta.xml.gz", NULL);
+ if (wordexp(tmpl, &word_vector, WRDE_REUSE) || word_vector.we_wordc < 1)
+ goto fail;
+ hy_repo_set_string(repo, HY_REPO_PRESTO_FN, word_vector.we_wordv[0]);
+
+ tmpl = pool_tmpjoin(pool, path, "/*updateinfo.xml.gz", NULL);
+ if (wordexp(tmpl, &word_vector, WRDE_REUSE) || word_vector.we_wordc < 1)
+ goto fail;
+ hy_repo_set_string(repo, HY_REPO_UPDATEINFO_FN, word_vector.we_wordv[0]);
+
+ wordfree(&word_vector);
+ return repo;
+
+ fail:
+ wordfree(&word_vector);
+ hy_repo_free(repo);
+ return NULL;
+}
+
+int
+load_repo(Pool *pool, const char *name, const char *path, int installed)
+{
+ HyRepo hrepo = hy_repo_create(name);
+ Repo *r = repo_create(pool, name);
+ libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(r);
+ hy_repo_free(hrepo);
+
+ FILE *fp = fopen(path, "r");
+
+ if (!fp)
+ return 1;
+ testcase_add_testtags(r, fp, 0);
+ if (installed)
+ pool_set_installed(pool, r);
+ fclose(fp);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TESTSHARED_H
+#define TESTSHARED_H
+
+#include "libdnf/hy-repo.h"
+
+#include <solv/pooltypes.h>
+
+#define UNITTEST_DIR "/tmp/hawkeyXXXXXX"
+#define YUM_DIR_SUFFIX "yum/repodata/"
+#define YUM_REPO_NAME "nevermac"
+#define TEST_FIXED_ARCH "x86_64"
+#define TEST_EXPECT_SYSTEM_PKGS 14
+#define TEST_EXPECT_SYSTEM_NSOLVABLES TEST_EXPECT_SYSTEM_PKGS
+#define TEST_EXPECT_MAIN_NSOLVABLES 14
+#define TEST_EXPECT_UPDATES_NSOLVABLES 17
+#define TEST_EXPECT_YUM_NSOLVABLES 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HyRepo glob_for_repofiles(Pool *pool, const char *repo_name, const char *path);
+int load_repo(Pool *pool, const char *name, const char *path, int installed);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TESTSHARED_H */
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libdnf/hy-goal.h"
+#include "libdnf/hy-package.h"
+#include "libdnf/hy-package-private.hpp"
+#include "libdnf/hy-query.h"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-util.h"
+
+#include "testsys.h"
+
+#include <solv/repo.h>
+#include <solv/util.h>
+
+#include <check.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void
+assert_nevra_eq(DnfPackage *pkg, const char *nevra)
+{
+ const char *pkg_nevra = dnf_package_get_nevra(pkg);
+ ck_assert_str_eq(pkg_nevra, nevra);
+}
+
+DnfPackage *
+by_name(DnfSack *sack, const char *name)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, name);
+ GPtrArray *plist = hy_query_run(q);
+ hy_query_free(q);
+ auto pkg = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist, 0)));
+ g_ptr_array_unref(plist);
+
+ return pkg;
+}
+
+DnfPackage *
+by_name_repo(DnfSack *sack, const char *name, const char *repo)
+{
+ HyQuery q = hy_query_create(sack);
+ hy_query_filter(q, HY_PKG_NAME, HY_EQ, name);
+ hy_query_filter(q, HY_PKG_REPONAME, HY_EQ, repo);
+ GPtrArray *plist = hy_query_run(q);
+ hy_query_free(q);
+ auto pkg = static_cast<DnfPackage *>(g_object_ref(g_ptr_array_index(plist, 0)));
+ g_ptr_array_unref(plist);
+
+ return pkg;
+}
+
+void
+dump_packagelist(GPtrArray *plist, int free)
+{
+ for (guint i = 0; i < plist->len; ++i) {
+ auto pkg = static_cast<DnfPackage *>(g_ptr_array_index(plist, i));
+ Solvable *s = pool_id2solvable(dnf_package_get_pool(pkg), dnf_package_get_id(pkg));
+ const char *nvra = dnf_package_get_nevra(pkg);
+ printf("\t%s @%s\n", nvra, s->repo->name);
+ }
+ if (free)
+ g_ptr_array_unref(plist);
+}
+
+void
+dump_query_results(HyQuery query)
+{
+ GPtrArray *plist = hy_query_run(query);
+ dump_packagelist(plist, 1);
+}
+
+void
+dump_goal_results(HyGoal goal)
+{
+ printf("installs:\n");
+ dump_packagelist(hy_goal_list_installs(goal, NULL), 1);
+ printf("upgrades:\n");
+ dump_packagelist(hy_goal_list_upgrades(goal, NULL), 1);
+ printf("erasures:\n");
+ dump_packagelist(hy_goal_list_erasures(goal, NULL), 1);
+ printf("reinstalls:\n");
+ dump_packagelist(hy_goal_list_reinstalls(goal, NULL), 1);
+}
+
+int
+query_count_results(HyQuery query)
+{
+ GPtrArray *plist = hy_query_run(query);
+ int ret = plist->len;
+ g_ptr_array_unref(plist);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TESTSYS_H
+#define TESTSYS_H
+
+
+#include <solv/pooltypes.h>
+
+
+#include "libdnf/dnf-sack.h"
+#include "testshared.h"
+
+void assert_nevra_eq(DnfPackage *pkg, const char *nevra);
+DnfPackage *by_name(DnfSack *sack, const char *name);
+DnfPackage *by_name_repo(DnfSack *sack, const char *name, const char *repo);
+void dump_packagelist(GPtrArray *plist, int free);
+void dump_query_results(HyQuery query);
+void dump_goal_results(HyGoal goal);
+int query_count_results(HyQuery query);
+
+#endif /* TESTSYS_H */
--- /dev/null
+add_executable(test_libdnf_main dnf-self-test.c)
+
+configure_file(${CMAKE_SOURCE_DIR}/data/tests/modules/yum.repos.d/test.repo.in ${CMAKE_SOURCE_DIR}/data/tests/modules/yum.repos.d/test.repo @ONLY)
+
+target_link_libraries(test_libdnf_main
+ libdnf
+ ${REPO_LIBRARIES}
+ ${GLIB_LIBRARIES}
+ ${GLIB_GOBJECT_LIBRARIES}
+ ${GLIB_GIO_LIBRARIES}
+ ${GLIB_GIO_UNIX_LIBRARIES}
+ ${SOLV_LIBRARY}
+ ${SOLVEXT_LIBRARY}
+ ${RPMDB_LIBRARY}
+)
+
+add_test(test_libdnf_main test_libdnf_main)
+
+# ASAN_OPTIONS fix the "ASan runtime does not come first in initial library
+# list" message. Note the better solution should be to use LD_PRELOAD=`ls
+# /lib64/libasan.so.?`. With the solution used here the sanitizer library is
+# loaded when the DSO linked against it is loaded. For any calls up to that
+# point the sanitizers aren't active. While hackish, this is convenient because
+# e.g. python is causing some leaks during module loading which this works
+# around.
+set_property(TEST test_libdnf_main PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/libdnf;ASAN_OPTIONS=verify_asan_link_order=0")
--- /dev/null
+#ifndef LIBDNF_TESTS_BACKPORTS_HPP
+#define LIBDNF_TESTS_BACKPORTS_HPP
+
+#include <ostream>
+#include <type_traits>
+
+// fix CPPUNIT_ASSERT_EQUAL for enums in CppUnit < 1.14
+template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
+std::ostream & operator <<(std::ostream & out, E e) {
+ return out << static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+#endif // LIBDNF_TESTS_BACKPORTS_HPP
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigParserTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ConfigParserTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include "ConfigParserTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ConfigParserTest);
+
+void ConfigParserTest::setUp()
+{}
+
+void ConfigParserTest::testConfigParserReleasever()
+{
+ {
+ // Test $releasever_major, $releasever_minor
+ std::map<std::string, std::string> substitutions = {
+ {"releasever", "1.23"},
+ };
+
+ std::string text = "major: $releasever_major, minor: $releasever_minor";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "major: 1, minor: 23");
+
+ text = "full releasever: $releasever";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "full releasever: 1.23");
+ }
+ {
+ // Test with empty $releasever, should set empty $releasever_major, $releasever_minor
+ std::map<std::string, std::string> substitutions = {
+ {"releasever", ""},
+ };
+ std::string text = "major: $releasever_major, minor: $releasever_minor";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "major: , minor: ");
+ }
+ {
+ std::map<std::string, std::string> substitutions = {
+ {"var1", "value123"},
+ {"var2", "456"},
+ };
+ std::string text = "foo$var1-bar";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "foovalue123-bar");
+
+ text = "${var1:+alternate}-${unset:-default}-${nn:+n${nn:-${nnn:}";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "alternate-default-${nn:+n${nn:-${nnn:}");
+
+ text = "${unset:-${var1:+${var2:+$var2}}}";
+ libdnf::ConfigParser::substitute(text, substitutions);
+ CPPUNIT_ASSERT(text == "456");
+ }
+}
--- /dev/null
+#ifndef LIBDNF_CONFIGPARSERTEST_HPP
+#define LIBDNF_CONFIGPARSERTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <libdnf/conf/ConfigParser.hpp>
+
+class ConfigParserTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ConfigParserTest);
+ CPPUNIT_TEST(testConfigParserReleasever);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void testConfigParserReleasever();
+
+};
+
+#endif // LIBDNF_CONFIGPARSERTEST_HPP
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 2008-2015 Richard Hughes <richard@hughsie.com>
+ *
+ * Most of this code was taken from Dnf, libzif/zif-self-test.c
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libdnf/libdnf.h"
+
+#include <glib-object.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <glib/gstdio.h>
+
+/**
+ * cd_test_get_filename:
+ **/
+static gchar *
+dnf_test_get_filename(const gchar *filename)
+{
+ char full_tmp[PATH_MAX];
+ gchar *full = NULL;
+ gchar *path;
+ gchar *tmp;
+
+ path = g_build_filename(TESTDATADIR, filename, NULL);
+ tmp = realpath(path, full_tmp);
+ if (tmp == NULL)
+ goto out;
+ full = g_strdup(full_tmp);
+out:
+ g_free(path);
+ return full;
+}
+
+static guint _dnf_lock_state_changed = 0;
+
+static void
+dnf_lock_state_changed_cb(DnfLock *lock, guint bitfield, gpointer user_data)
+{
+ g_debug("lock state now %i", bitfield);
+ _dnf_lock_state_changed++;
+}
+
+static void
+dnf_lock_func(void)
+{
+ DnfLock *lock;
+ gboolean ret;
+ guint lock_id1;
+ guint lock_id2;
+ GError *error = NULL;
+
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+ g_assert(lock != NULL);
+ g_signal_connect(lock, "state-changed",
+ G_CALLBACK(dnf_lock_state_changed_cb), NULL);
+
+ /* nothing yet! */
+ g_assert_cmpint(dnf_lock_get_state(lock), ==, 0);
+ ret = dnf_lock_release(lock, 999, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR);
+ g_assert(!ret);
+ g_clear_error(&error);
+
+ /* take one */
+ lock_id1 = dnf_lock_take(lock,
+ DNF_LOCK_TYPE_RPMDB,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert(lock_id1 != 0);
+ g_assert_cmpint(dnf_lock_get_state(lock), ==, 1 << DNF_LOCK_TYPE_RPMDB);
+ g_assert_cmpint(_dnf_lock_state_changed, ==, 1);
+
+ /* take a different one */
+ lock_id2 = dnf_lock_take(lock,
+ DNF_LOCK_TYPE_REPO,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert(lock_id2 != 0);
+ g_assert(lock_id2 != lock_id1);
+ g_assert_cmpint(dnf_lock_get_state(lock), ==, 1 << DNF_LOCK_TYPE_RPMDB | 1 << DNF_LOCK_TYPE_REPO);
+ g_assert_cmpint(_dnf_lock_state_changed, ==, 2);
+
+ /* take two */
+ lock_id1 = dnf_lock_take(lock,
+ DNF_LOCK_TYPE_RPMDB,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert(lock_id1 != 0);
+ g_assert_cmpint(dnf_lock_get_state(lock), ==, 1 << DNF_LOCK_TYPE_RPMDB | 1 << DNF_LOCK_TYPE_REPO);
+
+ /* release one */
+ ret = dnf_lock_release(lock, lock_id1, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* release different one */
+ ret = dnf_lock_release(lock, lock_id2, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* release two */
+ ret = dnf_lock_release(lock, lock_id1, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* no more! */
+ ret = dnf_lock_release(lock, lock_id1, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR);
+ g_assert(!ret);
+ g_clear_error(&error);
+ g_assert_cmpint(dnf_lock_get_state(lock), ==, 0);
+ g_assert_cmpint(_dnf_lock_state_changed, ==, 6);
+
+ g_object_unref(lock);
+}
+
+static gpointer
+dnf_self_test_lock_thread_one(gpointer data)
+{
+ GError *error = NULL;
+ guint lock_id;
+ DnfLock *lock = DNF_LOCK(data);
+
+ g_usleep(G_USEC_PER_SEC / 100);
+ lock_id = dnf_lock_take(lock,
+ DNF_LOCK_TYPE_REPO,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_CANNOT_GET_LOCK);
+ g_assert_cmpint(lock_id, ==, 0);
+ g_error_free(error);
+ return NULL;
+}
+
+static void
+dnf_lock_threads_func(void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ GThread *one;
+ guint lock_id;
+ DnfLock *lock;
+
+ /* take in parent thread */
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+ lock_id = dnf_lock_take(lock,
+ DNF_LOCK_TYPE_REPO,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert_cmpint(lock_id, >, 0);
+
+ /* attempt to take in child thread(should fail) */
+ one = g_thread_new("dnf-lock-one",
+ dnf_self_test_lock_thread_one,
+ lock);
+
+ /* block, waiting for thread */
+ g_usleep(G_USEC_PER_SEC);
+
+ /* release lock */
+ ret = dnf_lock_release(lock, lock_id, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ g_thread_unref(one);
+ g_object_unref(lock);
+}
+
+static void
+ch_test_repo_func(void)
+{
+ DnfRepo *repo;
+ DnfContext *context;
+ context = dnf_context_new();
+ repo = dnf_repo_new(context);
+ g_object_unref(repo);
+ g_object_unref(context);
+}
+
+static void
+dnf_repo_setup_with_empty_keyfile(void)
+{
+ DnfContext *context = dnf_context_new();
+ dnf_context_set_release_ver(context, "33");
+ DnfRepo *repo = dnf_repo_new(context);
+ GKeyFile *empty_key_file = g_key_file_new();
+
+ dnf_repo_set_keyfile(repo, empty_key_file);
+
+ GError *error = NULL;
+ // Empty key file is not an errror, there is just no configuration to be loaded.
+ g_assert(dnf_repo_setup(repo, &error));
+ g_assert_no_error(error);
+
+ g_object_unref(repo);
+ g_object_unref(context);
+ g_key_file_free(empty_key_file);
+}
+
+static guint _allow_cancel_updates = 0;
+static guint _action_updates = 0;
+static guint _package_progress_updates = 0;
+static guint _last_percent = 0;
+static guint _updates = 0;
+
+static void
+dnf_state_test_percentage_changed_cb(DnfState *state, guint value, gpointer data)
+{
+ _last_percent = value;
+ _updates++;
+}
+
+static void
+dnf_state_test_allow_cancel_changed_cb(DnfState *state, gboolean allow_cancel, gpointer data)
+{
+ _allow_cancel_updates++;
+}
+
+static void
+dnf_state_test_action_changed_cb(DnfState *state, DnfStateAction action, gpointer data)
+{
+ _action_updates++;
+}
+
+static void
+dnf_state_test_package_progress_changed_cb(DnfState *state,
+ const gchar *dnf_package_get_id,
+ DnfStateAction action,
+ guint percentage,
+ gpointer data)
+{
+ g_assert(data == NULL);
+ _package_progress_updates++;
+}
+
+#define DNF_STATE_ACTION_DOWNLOAD 1
+#define DNF_STATE_ACTION_DEP_RESOLVE 2
+#define DNF_STATE_ACTION_LOADING_CACHE 3
+
+static void
+dnf_state_func(void)
+{
+ gboolean ret;
+ DnfState *state;
+
+ _updates = 0;
+
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ g_assert(state != NULL);
+ g_signal_connect(state, "percentage-changed", G_CALLBACK(dnf_state_test_percentage_changed_cb), NULL);
+ g_signal_connect(state, "allow-cancel-changed", G_CALLBACK(dnf_state_test_allow_cancel_changed_cb), NULL);
+ g_signal_connect(state, "action-changed", G_CALLBACK(dnf_state_test_action_changed_cb), NULL);
+ g_signal_connect(state, "package-progress-changed", G_CALLBACK(dnf_state_test_package_progress_changed_cb), NULL);
+
+ g_assert(dnf_state_get_allow_cancel(state));
+ g_assert_cmpint(dnf_state_get_action(state), ==, DNF_STATE_ACTION_UNKNOWN);
+
+ dnf_state_set_allow_cancel(state, TRUE);
+ g_assert(dnf_state_get_allow_cancel(state));
+
+ dnf_state_set_allow_cancel(state, FALSE);
+ g_assert(!dnf_state_get_allow_cancel(state));
+ g_assert_cmpint(_allow_cancel_updates, ==, 1);
+
+ /* stop never started */
+ g_assert(!dnf_state_action_stop(state));
+
+ /* repeated */
+ g_assert(dnf_state_action_start(state, DNF_STATE_ACTION_DOWNLOAD, NULL));
+ g_assert(!dnf_state_action_start(state, DNF_STATE_ACTION_DOWNLOAD, NULL));
+ g_assert_cmpint(dnf_state_get_action(state), ==, DNF_STATE_ACTION_DOWNLOAD);
+ g_assert(dnf_state_action_stop(state));
+ g_assert_cmpint(dnf_state_get_action(state), ==, DNF_STATE_ACTION_UNKNOWN);
+ g_assert_cmpint(_action_updates, ==, 2);
+
+ ret = dnf_state_set_number_steps(state, 5);
+ g_assert(ret);
+
+ ret = dnf_state_done(state, NULL);
+ g_assert(ret);
+
+ g_assert_cmpint(_updates, ==, 1);
+
+ g_assert_cmpint(_last_percent, ==, 20);
+
+ ret = dnf_state_done(state, NULL);
+ g_assert(ret);
+ ret = dnf_state_done(state, NULL);
+ g_assert(ret);
+ ret = dnf_state_done(state, NULL);
+ g_assert(ret);
+ dnf_state_set_package_progress(state,
+ "hal;0.0.1;i386;fedora",
+ DNF_STATE_ACTION_DOWNLOAD,
+ 50);
+ g_assert(dnf_state_done(state, NULL));
+
+ g_assert(!dnf_state_done(state, NULL));
+ g_assert_cmpint(_updates, ==, 5);
+ g_assert_cmpint(_package_progress_updates, ==, 1);
+ g_assert_cmpint(_last_percent, ==, 100);
+
+ /* ensure allow cancel as we're done */
+ g_assert(dnf_state_get_allow_cancel(state));
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_child_func(void)
+{
+ gboolean ret;
+ DnfState *state;
+ DnfState *child;
+
+ /* reset */
+ _updates = 0;
+ _allow_cancel_updates = 0;
+ _action_updates = 0;
+ _package_progress_updates = 0;
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ dnf_state_set_allow_cancel(state, TRUE);
+ dnf_state_set_number_steps(state, 2);
+ g_signal_connect(state, "percentage-changed", G_CALLBACK(dnf_state_test_percentage_changed_cb), NULL);
+ g_signal_connect(state, "allow-cancel-changed", G_CALLBACK(dnf_state_test_allow_cancel_changed_cb), NULL);
+ g_signal_connect(state, "action-changed", G_CALLBACK(dnf_state_test_action_changed_cb), NULL);
+ g_signal_connect(state, "package-progress-changed", G_CALLBACK(dnf_state_test_package_progress_changed_cb), NULL);
+
+ // state: |-----------------------|-----------------------|
+ // step1: |-----------------------|
+ // child: |-------------|---------|
+
+ /* PARENT UPDATE */
+ g_debug("parent update #1");
+ ret = dnf_state_done(state, NULL);
+
+ g_assert(ret);
+ g_assert((_updates == 1));
+ g_assert((_last_percent == 50));
+
+ /* set parent state */
+ g_debug("setting: depsolving-conflicts");
+ dnf_state_action_start(state,
+ DNF_STATE_ACTION_DEP_RESOLVE,
+ "hal;0.1.0-1;i386;fedora");
+
+ /* now test with a child */
+ child = dnf_state_get_child(state);
+ dnf_state_set_number_steps(child, 2);
+
+ /* check child inherits parents action */
+ g_assert_cmpint(dnf_state_get_action(child), ==,
+ DNF_STATE_ACTION_DEP_RESOLVE);
+
+ /* set child non-cancellable */
+ dnf_state_set_allow_cancel(child, FALSE);
+
+ /* ensure both are disallow-cancel */
+ g_assert(!dnf_state_get_allow_cancel(child));
+ g_assert(!dnf_state_get_allow_cancel(state));
+
+ /* CHILD UPDATE */
+ g_debug("setting: loading-rpmdb");
+ g_assert(dnf_state_action_start(child, DNF_STATE_ACTION_LOADING_CACHE, NULL));
+ g_assert_cmpint(dnf_state_get_action(child), ==,
+ DNF_STATE_ACTION_LOADING_CACHE);
+
+ g_debug("child update #1");
+ ret = dnf_state_done(child, NULL);
+ g_assert(ret);
+ dnf_state_set_package_progress(child,
+ "hal;0.0.1;i386;fedora",
+ DNF_STATE_ACTION_DOWNLOAD,
+ 50);
+
+ g_assert_cmpint(_updates, ==, 2);
+ g_assert_cmpint(_last_percent, ==, 75);
+ g_assert_cmpint(_package_progress_updates, ==, 1);
+
+ /* child action */
+ g_debug("setting: downloading");
+ g_assert(dnf_state_action_start(child,
+ DNF_STATE_ACTION_DOWNLOAD,
+ NULL));
+ g_assert_cmpint(dnf_state_get_action(child), ==,
+ DNF_STATE_ACTION_DOWNLOAD);
+
+ /* CHILD UPDATE */
+ g_debug("child update #2");
+ ret = dnf_state_done(child, NULL);
+
+ g_assert(ret);
+ g_assert_cmpint(dnf_state_get_action(state), ==,
+ DNF_STATE_ACTION_DEP_RESOLVE);
+ g_assert(dnf_state_action_stop(state));
+ g_assert(!dnf_state_action_stop(state));
+ g_assert_cmpint(dnf_state_get_action(state), ==,
+ DNF_STATE_ACTION_UNKNOWN);
+ g_assert_cmpint(_action_updates, ==, 6);
+
+ g_assert_cmpint(_updates, ==, 3);
+ g_assert_cmpint(_last_percent, ==, 100);
+
+ /* ensure the child finishing cleared the allow cancel on the parent */
+ ret = dnf_state_get_allow_cancel(state);
+ g_assert(ret);
+
+ /* PARENT UPDATE */
+ g_debug("parent update #2");
+ ret = dnf_state_done(state, NULL);
+ g_assert(ret);
+
+ /* ensure we ignored the duplicate */
+ g_assert_cmpint(_updates, ==, 3);
+ g_assert_cmpint(_last_percent, ==, 100);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_parent_one_step_proxy_func(void)
+{
+ DnfState *state;
+ DnfState *child;
+
+ /* reset */
+ _updates = 0;
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ dnf_state_set_number_steps(state, 1);
+ g_signal_connect(state, "percentage-changed", G_CALLBACK(dnf_state_test_percentage_changed_cb), NULL);
+ g_signal_connect(state, "allow-cancel-changed", G_CALLBACK(dnf_state_test_allow_cancel_changed_cb), NULL);
+
+ /* now test with a child */
+ child = dnf_state_get_child(state);
+ dnf_state_set_number_steps(child, 2);
+
+ /* CHILD SET VALUE */
+ dnf_state_set_percentage(child, 33);
+
+ /* ensure 1 updates for state with one step and ensure using child value as parent */
+ g_assert(_updates == 1);
+ g_assert(_last_percent == 33);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_non_equal_steps_func(void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ DnfState *state;
+ DnfState *child;
+ DnfState *child_child;
+
+ /* test non-equal steps */
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ dnf_state_set_enable_profile(state, TRUE);
+ ret = dnf_state_set_steps(state,
+ &error,
+ 20, /* prepare */
+ 60, /* download */
+ 10, /* install */
+ -1);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR);
+ g_assert(!ret);
+ g_clear_error(&error);
+
+ /* okay this time */
+ ret = dnf_state_set_steps(state, &error, 20, 60, 20, -1);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify nothing */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 0);
+
+ /* child step should increment according to the custom steps */
+ child = dnf_state_get_child(state);
+ dnf_state_set_number_steps(child, 2);
+
+ /* start child */
+ g_usleep(9 * 10 * 1000);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify 10% */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 10);
+
+ /* finish child */
+ g_usleep(9 * 10 * 1000);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify 20% */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 20);
+
+ /* child step should increment according to the custom steps */
+ child = dnf_state_get_child(state);
+ ret = dnf_state_set_steps(child,
+ &error,
+ 25,
+ 75,
+ -1);
+ g_assert(ret);
+
+ /* start child */
+ g_usleep(25 * 10 * 1000);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify bilinear interpolation is working */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 35);
+
+ /*
+ * 0 20 80 100
+ * |---------||----------------------------||---------|
+ * | 35 |
+ * |-------||-------------------|(25%)
+ * | 75.5 |
+ * |---------------||--|(90%)
+ */
+ child_child = dnf_state_get_child(child);
+ ret = dnf_state_set_steps(child_child,
+ &error,
+ 90,
+ 10,
+ -1);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ ret = dnf_state_done(child_child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify bilinear interpolation(twice) is working for subpercentage */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 75);
+
+ ret = dnf_state_done(child_child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* finish child */
+ g_usleep(25 * 10 * 1000);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify 80% */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 80);
+
+ g_usleep(19 * 10 * 1000);
+
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* verify 100% */
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 100);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_no_progress_func(void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ DnfState *state;
+ DnfState *child;
+
+ /* test a state where we don't care about progress */
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ dnf_state_set_report_progress(state, FALSE);
+
+ dnf_state_set_number_steps(state, 3);
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 0);
+
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 0);
+
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ child = dnf_state_get_child(state);
+ g_assert(child != NULL);
+ dnf_state_set_number_steps(child, 2);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+ ret = dnf_state_done(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+ g_assert_cmpint(dnf_state_get_percentage(state), ==, 0);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_finish_func(void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ DnfState *state;
+ DnfState *child;
+
+ /* check straight finish */
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ dnf_state_set_number_steps(state, 3);
+
+ child = dnf_state_get_child(state);
+ dnf_state_set_number_steps(child, 3);
+ ret = dnf_state_finished(child, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* parent step done after child finish */
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_speed_func(void)
+{
+ DnfState *state;
+
+ /* speed averaging test */
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 0);
+ dnf_state_set_speed(state, 100);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 100);
+ dnf_state_set_speed(state, 200);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 150);
+ dnf_state_set_speed(state, 300);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 200);
+ dnf_state_set_speed(state, 400);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 250);
+ dnf_state_set_speed(state, 500);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 300);
+ dnf_state_set_speed(state, 600);
+ g_assert_cmpint(dnf_state_get_speed(state), ==, 400);
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_finished_func(void)
+{
+ DnfState *state_local;
+ DnfState *state;
+ gboolean ret;
+ GError *error = NULL;
+ guint i;
+
+ state = dnf_state_new();
+ g_object_add_weak_pointer(G_OBJECT(state),(gpointer *) &state);
+ ret = dnf_state_set_steps(state,
+ &error,
+ 90,
+ 10,
+ -1);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ dnf_state_set_allow_cancel(state, FALSE);
+ dnf_state_action_start(state,
+ DNF_STATE_ACTION_LOADING_CACHE, "/");
+
+ state_local = dnf_state_get_child(state);
+ dnf_state_set_report_progress(state_local, FALSE);
+
+ for (i = 0; i < 10; i++) {
+ /* check cancelled(okay to reuse as we called
+ * dnf_state_set_report_progress before)*/
+ ret = dnf_state_done(state_local, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+ }
+
+ /* turn checks back on */
+ dnf_state_set_report_progress(state_local, TRUE);
+ ret = dnf_state_finished(state_local, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* this section done */
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* this section done */
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ g_object_unref(state);
+ g_assert(state == NULL);
+}
+
+static void
+dnf_state_locking_func(void)
+{
+ gboolean ret;
+ GError *error = NULL;
+ DnfState *state;
+ DnfLock *lock;
+
+ /* set, as is singleton */
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+
+ state = dnf_state_new();
+
+ /* lock once */
+ ret = dnf_state_take_lock(state,
+ DNF_LOCK_TYPE_RPMDB,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* succeeded, even again */
+ ret = dnf_state_take_lock(state,
+ DNF_LOCK_TYPE_RPMDB,
+ DNF_LOCK_MODE_PROCESS,
+ &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ g_object_unref(state);
+ g_object_unref(lock);
+}
+
+static void
+dnf_state_small_step_func(void)
+{
+ DnfState *state;
+ gboolean ret;
+ GError *error = NULL;
+ guint i;
+
+ _updates = 0;
+
+ state = dnf_state_new();
+ g_signal_connect(state, "percentage-changed",
+ G_CALLBACK(dnf_state_test_percentage_changed_cb), NULL);
+ dnf_state_set_number_steps(state, 100000);
+
+ /* process all steps, we should get 100 callbacks */
+ for (i = 0; i < 100000; i++) {
+ ret = dnf_state_done(state, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+ }
+ g_assert_cmpint(_updates, ==, 100);
+
+ g_object_unref(state);
+}
+
+static void
+dnf_repo_loader_func(void)
+{
+ GError *error = NULL;
+ DnfRepo *repo;
+ DnfState *state;
+ gboolean ret;
+ g_autofree gchar *repos_dir = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autoptr(DnfRepoLoader) repo_loader = NULL;
+ guint metadata_expire;
+
+ /* set up local context */
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("yum.repos.d");
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* use this as a throw-away */
+ state = dnf_context_get_state(ctx);
+
+ /* load repos that need keyfile fixes */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "bumblebee", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+ g_assert_cmpint(dnf_repo_get_kind(repo), ==, DNF_REPO_KIND_REMOTE);
+ g_assert(dnf_repo_get_gpgcheck(repo));
+ g_assert(!dnf_repo_get_gpgcheck_md(repo));
+
+ /* load repos that should be metadata enabled automatically */
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "redhat", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+ g_assert_cmpint(dnf_repo_get_enabled(repo), ==, DNF_REPO_ENABLED_METADATA);
+ g_assert_cmpint(dnf_repo_get_kind(repo), ==, DNF_REPO_KIND_REMOTE);
+ g_assert(!dnf_repo_get_gpgcheck(repo));
+ g_assert(!dnf_repo_get_gpgcheck_md(repo));
+
+ /* load local metadata repo */
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "local", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+ g_assert_cmpint(dnf_repo_get_enabled(repo), ==, DNF_REPO_ENABLED_METADATA |
+ DNF_REPO_ENABLED_PACKAGES);
+ g_assert_cmpint(dnf_repo_get_kind(repo), ==, DNF_REPO_KIND_LOCAL);
+ g_assert(!dnf_repo_get_gpgcheck(repo));
+ g_assert(!dnf_repo_get_gpgcheck_md(repo));
+
+ /* try to clean local repo */
+ ret = dnf_repo_clean(repo, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* try to refresh local repo */
+ dnf_state_reset(state);
+ ret = dnf_repo_update(repo, DNF_REPO_UPDATE_FLAG_NONE, state, &error);
+ /* check the metadata expire attribute */
+ metadata_expire = dnf_repo_get_metadata_expire(repo);
+ g_assert_cmpuint(metadata_expire, == , 60 * 60 * 24);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* try to check local repo that will not exist */
+ dnf_state_reset(state);
+ ret = dnf_repo_check(repo, 1, state, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_REPO_NOT_AVAILABLE);
+ g_assert(!ret);
+ g_clear_error(&error);
+}
+
+static void
+dnf_context_func(void)
+{
+ GError *error = NULL;
+ DnfContext *ctx;
+ gboolean ret;
+
+ ctx = dnf_context_new();
+ dnf_context_set_solv_dir(ctx, "/tmp/hawkey");
+ dnf_context_set_repo_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ g_assert_cmpstr(dnf_context_get_base_arch(ctx), !=, NULL);
+ g_assert_cmpstr(dnf_context_get_os_info(ctx), !=, NULL);
+ g_assert_cmpstr(dnf_context_get_arch_info(ctx), !=, NULL);
+ g_assert_cmpstr(dnf_context_get_release_ver(ctx), !=, NULL);
+ g_assert_cmpstr(dnf_context_get_cache_dir(ctx), ==, NULL);
+ g_assert_cmpstr(dnf_context_get_repo_dir(ctx), ==, "/tmp");
+ g_assert_cmpstr(dnf_context_get_solv_dir(ctx), ==, "/tmp/hawkey");
+ g_assert(dnf_context_get_check_disk_space(ctx));
+ g_assert(dnf_context_get_check_transaction(ctx));
+ dnf_context_set_keep_cache(ctx, FALSE);
+ g_assert(!dnf_context_get_keep_cache(ctx));
+
+ dnf_context_set_cache_dir(ctx, "/var");
+ dnf_context_set_repo_dir(ctx, "/etc");
+ g_assert_cmpstr(dnf_context_get_cache_dir(ctx), ==, "/var");
+ g_assert_cmpstr(dnf_context_get_repo_dir(ctx), ==, "/etc");
+
+ g_object_unref(ctx);
+}
+
+static void
+dnf_repo_loader_gpg_no_pubkey_func(void)
+{
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+
+ /* set up local context */
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("gpg-no-pubkey");
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_FILE_INVALID);
+ g_assert(!ret);
+}
+
+static void
+dnf_repo_loader_gpg_no_asc_func(void)
+{
+ DnfRepoLoader *repo_loader;
+ DnfRepo *repo;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autoptr(DnfState) state = NULL;
+ g_autoptr(DnfLock) lock = NULL;
+
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+
+ /* set up local context */
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("gpg-no-asc/yum.repos.d");
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* get the repo with no repomd.xml.asc */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "gpg-repo-no-asc", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+
+ /* check, which should fail as no local repomd.xml.asc exists */
+ state = dnf_state_new();
+ ret = dnf_repo_check(repo, G_MAXUINT, state, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_REPO_NOT_AVAILABLE);
+ g_assert(!ret);
+ g_clear_error(&error);
+
+ /* update, which should fail as no *remote* repomd.xml.asc exists */
+ dnf_state_reset(state);
+ ret = dnf_repo_update(repo,
+ DNF_REPO_UPDATE_FLAG_FORCE |
+ DNF_REPO_UPDATE_FLAG_SIMULATE,
+ state, &error);
+ if (g_error_matches(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG)) {
+ g_debug("skipping tests: %s", error->message);
+ return;
+ }
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_CANNOT_FETCH_SOURCE);
+ g_assert(!ret);
+ g_clear_error(&error);
+}
+
+static void
+dnf_repo_loader_gpg_wrong_asc_func(void)
+{
+ DnfRepoLoader *repo_loader;
+ DnfRepo *repo;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autoptr(DnfState) state = NULL;
+ g_autoptr(DnfLock) lock = NULL;
+
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+
+ /* set up local context */
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("gpg-wrong-asc/yum.repos.d");
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* get the repo with the *wrong* remote repomd.xml.asc */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "gpg-repo-wrong-asc", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+
+ /* update, which should fail as the repomd.xml.asc key is wrong */
+ state = dnf_state_new();
+ ret = dnf_repo_update(repo,
+ DNF_REPO_UPDATE_FLAG_FORCE |
+ DNF_REPO_UPDATE_FLAG_SIMULATE,
+ state, &error);
+ if (g_error_matches(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG)) {
+ g_debug("skipping tests: %s", error->message);
+ return;
+ }
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_CANNOT_FETCH_SOURCE);
+ g_assert(!ret);
+ g_clear_error(&error);
+}
+
+static void
+dnf_repo_loader_gpg_asc_func(void)
+{
+ DnfRepoLoader *repo_loader;
+ DnfRepo *repo;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autoptr(DnfState) state = NULL;
+ g_autoptr(DnfLock) lock = NULL;
+
+ lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+
+ /* set up local context */
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("gpg-asc/yum.repos.d");
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* get the repo with no repomd.xml.asc */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "gpg-repo-asc", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+
+ /* check, which should fail as there's no gnupg homedir with the key */
+ state = dnf_state_new();
+ ret = dnf_repo_check(repo, G_MAXUINT, state, &error);
+ g_assert_error(error, DNF_ERROR, DNF_ERROR_REPO_NOT_AVAILABLE);
+ g_assert(!ret);
+ g_clear_error(&error);
+
+ /* update, which should pass as a valid remote repomd.xml.asc exists */
+ dnf_state_reset(state);
+ ret = dnf_repo_update(repo,
+ DNF_REPO_UPDATE_FLAG_FORCE |
+ DNF_REPO_UPDATE_FLAG_SIMULATE,
+ state, &error);
+ if (g_error_matches(error,
+ DNF_ERROR,
+ DNF_ERROR_CANNOT_WRITE_REPO_CONFIG)) {
+ g_debug("skipping tests: %s", error->message);
+ return;
+ }
+ g_assert_no_error(error);
+ g_assert(ret);
+}
+
+static void
+dnf_repo_loader_cache_dir_check_func(void)
+{
+ DnfRepoLoader *repo_loader;
+ DnfRepo *repo;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autofree gchar *cache_dir = NULL;
+ const char *cache_location = NULL;
+ g_autofree gchar *expected_cache_suffix = NULL;
+
+ /* set up local context*/
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("cache-test/yum.repos.d");
+ cache_dir = g_build_filename(TESTDATADIR, "cache-test/cache-dir", NULL);
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ dnf_context_set_cache_dir(ctx, cache_dir);
+
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* get the testing repo */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "fedora", &error);
+ g_assert_no_error(error);
+ g_assert(repo != NULL);
+
+ /* check the repo location to verify it has the correct suffix */
+ cache_location = dnf_repo_get_location(repo);
+ expected_cache_suffix = g_strjoin("-", dnf_context_get_release_ver(ctx),
+ dnf_context_get_base_arch(ctx), NULL);
+ g_assert(g_str_has_suffix(cache_location, expected_cache_suffix));
+}
+
+
+static void
+touch_file(const char *filename)
+{
+ int touch_fd = open(filename, O_CREAT|O_WRONLY|O_NOCTTY, 0644);
+ g_assert_cmpint(touch_fd, !=, -1);
+ g_assert_cmpint(close(touch_fd), ==, 0);
+ g_assert(g_file_test(filename, G_FILE_TEST_EXISTS));
+}
+
+static void
+dnf_context_cache_clean_check_func(void)
+{
+
+ DnfRepoLoader *repo_loader;
+ DnfRepo *repo;
+ gboolean ret;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(DnfContext) ctx = NULL;
+ g_autofree gchar *repos_dir = NULL;
+ g_autofree gchar *cache_dir = NULL;
+ const gchar* repo_location;
+ guint file_result;
+
+ /* set up local context*/
+ ctx = dnf_context_new();
+ repos_dir = dnf_test_get_filename("cache-test/yum.repos.d");
+ cache_dir = g_build_filename(TESTDATADIR, "cache-test/cache-dir", NULL);
+ dnf_context_set_repo_dir(ctx, repos_dir);
+ dnf_context_set_solv_dir(ctx, "/tmp");
+ dnf_context_set_cache_dir(ctx, cache_dir);
+ dnf_context_set_lock_dir(ctx, cache_dir);
+
+ ret = dnf_context_setup(ctx, NULL, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* get the repo location */
+ repo_loader = dnf_repo_loader_new(ctx);
+ repo = dnf_repo_loader_get_repo_by_id(repo_loader, "fedora", &error);
+ repo_location = dnf_repo_get_location(repo);
+
+ /* Create test files for different flags */
+ g_autofree gchar* package_directory = g_build_filename(repo_location, "packages", NULL);
+ file_result = g_mkdir_with_parents(package_directory, 0777);
+ g_assert(file_result == 0);
+
+ /* File for Cleaning Metadata */
+ g_autofree gchar* repo_data_folder = g_build_filename(repo_location, "repodata", NULL);
+ file_result = g_mkdir_with_parents(repo_data_folder, 0777);
+ g_assert(file_result == 0);
+
+ g_autofree gchar* xml_string = g_build_filename(repo_location, "metalink.xml", NULL);
+ touch_file(xml_string);
+
+ /* File for Cleaning Expired Cache */
+ g_autofree gchar* expire_cache_file = g_build_filename(repo_location, "repomd.xml", NULL);
+ touch_file(expire_cache_file);
+
+ /* File that is not for any flag case, used for testing functionality */
+ g_autofree gchar* non_matching_file = g_build_filename(repo_location, "nomatch.xxx", NULL);
+ touch_file(non_matching_file);
+
+ /* Then we do the cleaning with dnf_clean_cache, to demonstate it works */
+ DnfContextCleanFlags flags = DNF_CONTEXT_CLEAN_EXPIRE_CACHE;
+ flags |= DNF_CONTEXT_CLEAN_PACKAGES;
+ flags |= DNF_CONTEXT_CLEAN_METADATA;
+
+ ret = dnf_context_clean_cache(ctx, flags, &error);
+ g_assert(ret);
+
+ /* Verify the functionality of the function */
+ g_assert(!g_file_test(package_directory, G_FILE_TEST_EXISTS));
+ g_assert(!g_file_test(repo_data_folder, G_FILE_TEST_EXISTS));
+ g_assert(!g_file_test(xml_string, G_FILE_TEST_EXISTS));
+ g_assert(!g_file_test(expire_cache_file, G_FILE_TEST_EXISTS));
+ g_assert(g_file_test(non_matching_file, G_FILE_TEST_EXISTS));
+
+ /* At this stage we clean up the files that we created for testing */
+ dnf_remove_recursive(cache_dir, &error);
+ g_assert_no_error(error);
+}
+
+int
+main(int argc, char **argv)
+{
+ g_assert(g_setenv("G_MESSAGES_DEBUG", "all", FALSE));
+ /* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
+ /* Also because we do valgrind testing and there are vast array of
+ * "leaks" when we load gio vfs modules.
+ */
+ g_assert(g_setenv ("GIO_USE_VFS", "local", TRUE));
+
+ g_test_init(&argc, &argv, NULL);
+
+ /* only critical and error are fatal */
+ g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+ g_log_set_always_fatal (G_LOG_FATAL_MASK);
+
+ /* Sets a variable to replace in repository configurations. */
+ g_assert(g_setenv("DNF_VAR_testdatadir", TESTDATADIR, TRUE));
+
+ /* tests go here */
+ g_test_add_func("/libdnf/repo_loader{gpg-asc}", dnf_repo_loader_gpg_asc_func);
+ g_test_add_func("/libdnf/repo_loader{gpg-wrong-asc}", dnf_repo_loader_gpg_wrong_asc_func);
+ g_test_add_func("/libdnf/repo_loader{gpg-no-asc}", dnf_repo_loader_gpg_no_asc_func);
+ g_test_add_func("/libdnf/repo_loader", dnf_repo_loader_func);
+ g_test_add_func("/libdnf/repo_loader{gpg-no-pubkey}", dnf_repo_loader_gpg_no_pubkey_func);
+ g_test_add_func("/libdnf/repo_loader{cache-dir-check}", dnf_repo_loader_cache_dir_check_func);
+ g_test_add_func("/libdnf/context", dnf_context_func);
+ g_test_add_func("/libdnf/context{cache-clean-check}", dnf_context_cache_clean_check_func);
+ g_test_add_func("/libdnf/lock", dnf_lock_func);
+ g_test_add_func("/libdnf/lock[threads]", dnf_lock_threads_func);
+ g_test_add_func("/libdnf/repo", ch_test_repo_func);
+ g_test_add_func("/libdnf/repo_empty_keyfile", dnf_repo_setup_with_empty_keyfile);
+ g_test_add_func("/libdnf/state", dnf_state_func);
+ g_test_add_func("/libdnf/state[child]", dnf_state_child_func);
+ g_test_add_func("/libdnf/state[parent-1-step]", dnf_state_parent_one_step_proxy_func);
+ g_test_add_func("/libdnf/state[no-equal]", dnf_state_non_equal_steps_func);
+ g_test_add_func("/libdnf/state[no-progress]", dnf_state_no_progress_func);
+ g_test_add_func("/libdnf/state[finish]", dnf_state_finish_func);
+ g_test_add_func("/libdnf/state[speed]", dnf_state_speed_func);
+ g_test_add_func("/libdnf/state[locking]", dnf_state_locking_func);
+ g_test_add_func("/libdnf/state[finished]", dnf_state_finished_func);
+ g_test_add_func("/libdnf/state[small-step]", dnf_state_small_step_func);
+
+ return g_test_run();
+}
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ContextTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackageContainerTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ContextTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackageContainerTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include "ContextTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ContextTest);
+
+#include "libdnf/dnf-context.hpp"
+#include "libdnf/dnf-repo-loader.h"
+#include "libdnf/sack/query.hpp"
+#include "libdnf/nevra.hpp"
+#include "libdnf/utils/File.hpp"
+#include "libdnf/sack/packageset.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+
+#include <memory>
+
+
+void ContextTest::setUp()
+{
+ dnf_context_set_config_file_path("");
+ context = dnf_context_new();
+}
+
+void ContextTest::tearDown()
+{
+ g_object_unref(context);
+}
+
+// XXX: look into sharing assert_list_names in the future
+static gboolean pkglist_has_nevra(GPtrArray *pkglist, const char *nevra)
+{
+ for (guint i = 0; i < pkglist->len; i++) {
+ DnfPackage *pkg = static_cast<DnfPackage *>(pkglist->pdata[i]);
+ if (g_str_equal(dnf_package_get_nevra(pkg), nevra))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void ContextTest::testLoadModules()
+{
+ GError *error = nullptr;
+
+ /* set up local context */
+ // set releasever to avoid crashing on missing /etc/os-release in the test data
+ dnf_context_set_release_ver(context, "26");
+ dnf_context_set_arch(context, "x86_64");
+ constexpr auto install_root = TESTDATADIR "/modules/";
+ dnf_context_set_install_root(context, install_root);
+ g_autoptr(DnfLock) lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+ constexpr auto repos_dir = TESTDATADIR "/modules/yum.repos.d/";
+ dnf_context_set_repo_dir(context, repos_dir);
+ dnf_context_set_solv_dir(context, "/tmp");
+ auto ret = dnf_context_setup(context, nullptr, &error);
+ g_assert_no_error(error);
+ g_assert(ret);
+
+ /* load local metadata repo */
+ DnfRepo *repo = dnf_repo_loader_get_repo_by_id(dnf_context_get_repo_loader(context), "test", &error);
+ g_assert_no_error(error);
+ g_assert(repo != nullptr);
+ g_assert_cmpint(dnf_repo_get_enabled(repo), ==, DNF_REPO_ENABLED_METADATA | DNF_REPO_ENABLED_PACKAGES);
+ g_assert_cmpint(dnf_repo_get_kind(repo), ==, DNF_REPO_KIND_LOCAL);
+
+ DnfState *state = dnf_state_new();
+ dnf_repo_check(repo, G_MAXUINT, state, &error);
+ g_object_unref(state);
+
+ // Setup platform to prevent logger critical message
+ dnf_context_set_platform_module(context, "platform:26");
+
+ state = dnf_context_get_state(context);
+ dnf_context_setup_sack(context, state, &error);
+ g_assert_no_error(error);
+
+ auto sack = dnf_context_get_sack(context);
+ auto moduleExcludes = std::unique_ptr<libdnf::PackageSet>(dnf_sack_get_module_excludes(sack));
+ CPPUNIT_ASSERT(moduleExcludes->size() != 0);
+
+ libdnf::ModulePackageContainer * c = dnf_sack_get_module_container(sack);
+ std::vector<libdnf::ModulePackage *> packages = c->getModulePackages();
+ for(auto const& package: packages) {
+ if (package->getName() == "httpd"){
+ // disabled stream
+ if (package->getStream() == "2.2")
+ sackHasNot(sack, package);
+ // default module:stream
+ if (package->getStream() == "2.4")
+ sackHas(sack, package);
+ }
+ }
+
+ {
+ libdnf::Query query{sack};
+ // no match with modular RPM $name -> keep
+ std::string nevra = "grub2-2.02-0.40.x86_64";
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, nevra.c_str());
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) >= 1);
+ auto package = dnf_package_new(sack, packageSet->operator[](0));
+ CPPUNIT_ASSERT(dnf_package_get_nevra(package) == nevra);
+ g_object_unref(package);
+ query.clear();
+ }
+
+ {
+ libdnf::Query query{sack};
+ // $name matches with modular RPM $name -> exclude
+ std::string nevra = "httpd-2.2.10-1.x86_64";
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, nevra.c_str());
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) == 0);
+ query.clear();
+ }
+
+ {
+ libdnf::Query query{sack};
+ // Provides: $name matches with modular RPM $name -> exclude
+ std::string nevra = "httpd-provides-name-3.0-1.x86_64";
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, nevra.c_str());
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) == 0);
+ query.clear();
+ }
+
+ {
+ libdnf::Query query{sack};
+ // Provides: $name = ... matches with modular RPM $name -> exclude
+ std::string nevra = "httpd-provides-name-version-release-3.0-1.x86_64";
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, nevra.c_str());
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) == 0);
+ query.clear();
+ }
+
+ // try to install a nonexistent module
+ const char *module_specs[] = {"nonexistent", NULL};
+ g_assert(!dnf_context_module_install(context, module_specs, &error));
+ g_assert(error);
+ g_assert(strstr(error->message, "Unable to resolve argument 'nonexistent'"));
+ g_clear_pointer(&error, g_error_free);
+
+ // wrong stream
+ module_specs[0] = "httpd:nonexistent";
+ g_assert(!dnf_context_module_install(context, module_specs, &error));
+ g_assert(error);
+ g_assert(strstr(error->message, "Unable to resolve argument 'httpd:nonexistent'"));
+ g_clear_pointer(&error, g_error_free);
+
+ // try to install non-existent profile
+ module_specs[0] = "httpd:2.4/nonexistent";
+ g_assert(!dnf_context_module_install(context, module_specs, &error));
+ g_assert(error);
+ g_assert(strstr(error->message, "No profile found matching 'nonexistent'"));
+ g_clear_pointer(&error, g_error_free);
+
+ // disable all modules
+ g_assert(dnf_context_module_disable_all(context, &error));
+ g_assert_no_error(error);
+
+ // installing a modular package should fail
+ g_assert(!dnf_context_install(context, "httpd-2.4.25-8.x86_64", &error));
+ g_assert(error);
+ g_assert(strstr(error->message, "No package matches 'httpd-2.4.25-8.x86_64'"));
+ g_clear_pointer(&error, g_error_free);
+
+ // reset all modules
+ g_assert(dnf_context_reset_all_modules(context, sack, &error));
+ g_assert_no_error(error);
+
+ // enable and install default profile from modulemd-defaults
+ module_specs[0] = "httpd:2.4";
+ g_assert(dnf_context_module_install(context, module_specs, &error));
+ g_assert_no_error(error);
+ HyGoal goal = dnf_context_get_goal(context);
+ g_assert_cmpint(hy_goal_run_flags(goal, DNF_NONE), ==, 0);
+ g_autoptr(GPtrArray) pkgs = hy_goal_list_installs(goal, &error);
+ g_assert_no_error(error);
+ g_assert(pkgs);
+ g_assert(pkglist_has_nevra(pkgs, "httpd-2.4.25-8.x86_64"));
+ g_assert(pkglist_has_nevra(pkgs, "libnghttp2-1.21.1-1.x86_64"));
+
+ // Verify we can install the default stream from modulemd-defaults.
+ // This would fail with EnableMultipleStreamsException if it didn't match
+ // the 2.4 stream since we enabled the 2.4 stream just above.
+ module_specs[0] = "httpd";
+ g_assert(dnf_context_module_install(context, module_specs, &error));
+ g_assert_no_error(error);
+}
+
+void ContextTest::sackHas(DnfSack * sack, libdnf::ModulePackage * pkg) const
+{
+ libdnf::Query query{sack};
+ auto artifacts = pkg->getArtifacts();
+ for(auto & artifact: artifacts) {
+ artifact = artifact.replace(artifact.find("-0:"), 3, "-");
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, artifact.c_str());
+
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) >= 1);
+ auto package = dnf_package_new(sack, packageSet->operator[](0));
+ CPPUNIT_ASSERT(dnf_package_get_nevra(package) == artifact);
+ g_object_unref(package);
+
+ query.clear();
+
+ }
+}
+
+void ContextTest::sackHasNot(DnfSack * sack, libdnf::ModulePackage * pkg) const
+{
+ libdnf::Query query{sack};
+ auto artifacts = pkg->getArtifacts();
+ for(auto & artifact: artifacts) {
+ artifact = artifact.replace(artifact.find("-0:"), 3, "-");
+ query.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, artifact.c_str());
+
+ auto packageSet = const_cast<libdnf::PackageSet *>(query.runSet());
+ CPPUNIT_ASSERT(dnf_packageset_count(packageSet) == 0);
+
+ query.clear();
+ }
+}
--- /dev/null
+#ifndef LIBDNF_CONTEXTTEST_HPP
+#define LIBDNF_CONTEXTTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "libdnf/dnf-context.hpp"
+#include "libdnf/module/modulemd/ModuleMetadata.hpp"
+
+class ContextTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ContextTest);
+ CPPUNIT_TEST(testLoadModules);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testLoadModules();
+
+private:
+ DnfContext *context;
+ void sackHas(DnfSack * sack, libdnf::ModulePackage * pkg) const;
+ void sackHasNot(DnfSack * sack, libdnf::ModulePackage * pkg) const;
+};
+
+#endif //LIBDNF_CONTEXTTEST_HPP
--- /dev/null
+#include "ModulePackageContainerTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ModulePackageContainerTest);
+
+#include "libdnf/log.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-iutil-private.hpp"
+
+#include <algorithm>
+
+#define UNITTEST_DIR "/tmp/libdnf22XXXXXX"
+
+void ModulePackageContainerTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+ tmpdir = g_strdup(UNITTEST_DIR);
+ char *retptr = mkdtemp(tmpdir);
+ CPPUNIT_ASSERT(retptr);
+ char * etc_target = g_strjoin(NULL, tmpdir, "/etc", NULL);
+ CPPUNIT_ASSERT(dnf_copy_recursive(TESTDATADIR "/modules/etc", etc_target, &error));
+ g_assert_no_error(error);
+ g_free(etc_target);
+
+ dnf_context_set_config_file_path("");
+ context = dnf_context_new();
+ dnf_context_set_release_ver(context, "26");
+ dnf_context_set_arch(context, "x86_64");
+ dnf_context_set_platform_module(context, "platform:26");
+ dnf_context_set_install_root(context, tmpdir);
+ g_autoptr(DnfLock) lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, tmpdir);
+ dnf_context_set_repo_dir(context, TESTDATADIR "/modules/yum.repos.d/");
+ dnf_context_set_solv_dir(context, tmpdir);
+ dnf_context_setup(context, nullptr, &error);
+ g_assert_no_error(error);
+
+ DnfState *state = dnf_context_get_state(context);
+ dnf_context_setup_sack(context, state, &error);
+ g_assert_no_error(error);
+
+ auto sack = dnf_context_get_sack(context);
+ modules = dnf_sack_get_module_container(sack);
+}
+
+void ModulePackageContainerTest::tearDown()
+{
+ g_autoptr(GError) error = nullptr;
+ g_object_unref(context);
+ dnf_remove_recursive_v2(tmpdir, &error);
+ g_assert_no_error(error);
+ g_free(tmpdir);
+}
+
+void ModulePackageContainerTest::testEnabledModules()
+{
+ // Starting environment has enabled modules, using older syntax to test backwards compatibility.
+ const std::vector<std::string> specs = {"httpd:2.4", "base-runtime:f26" };
+ for (const auto &spec : specs) {
+ const auto &qRes = modules->query(spec);
+ for (const auto &pkg : qRes)
+ CPPUNIT_ASSERT(modules->isEnabled(pkg->getName(), pkg->getStream()));
+ }
+}
+
+void ModulePackageContainerTest::testDisableEnableModules()
+{
+ // Starting environment has enabled modules, using older syntax to test backwards compatibility.
+ modules->disable("httpd");
+ modules->disable("base-runtime");
+
+ for (const auto & it : modules->getDisabledModules()) {
+ CPPUNIT_ASSERT(it == "httpd" || it == "base-runtime");
+ }
+
+ modules->save();
+
+ CPPUNIT_ASSERT(!modules->isEnabled("httpd", "2.4"));
+ CPPUNIT_ASSERT(!modules->isEnabled("httpd", "2.2"));
+ CPPUNIT_ASSERT(!modules->isEnabled("base-runtime", "f26"));
+
+ modules->enable("httpd", "2.4");
+ modules->enable("base-runtime", "f26");
+
+ for (const auto &it : modules->getEnabledStreams()) {
+ CPPUNIT_ASSERT(it.first == "httpd" || it.first == "base-runtime");
+ if (it.first == "httpd")
+ CPPUNIT_ASSERT(it.second == "2.4");
+ else
+ CPPUNIT_ASSERT(it.second == "f26");
+ }
+
+ modules->save();
+}
+
+void ModulePackageContainerTest::testRollback()
+{
+ // Starting environment has enabled modules, using older syntax to test backwards compatibility.
+ modules->disable("httpd");
+ modules->disable("base-runtime");
+
+ CPPUNIT_ASSERT(!modules->isEnabled("httpd", "2.4"));
+ CPPUNIT_ASSERT(!modules->isEnabled("base-runtime", "f26"));
+
+ modules->rollback();
+
+ CPPUNIT_ASSERT(modules->isEnabled("httpd", "2.4"));
+ CPPUNIT_ASSERT(modules->isEnabled("base-runtime", "f26"));
+}
+
+void ModulePackageContainerTest::testInstallRemoveProfile()
+{
+ modules->install("httpd", "2.4", "default");
+ {
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ auto it = std::find(installed.begin(), installed.end(), "default");
+ CPPUNIT_ASSERT(it != installed.end());
+ }
+
+ modules->install("httpd", "2.4", "doc");
+ {
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ auto it = std::find(installed.begin(), installed.end(), "doc");
+ CPPUNIT_ASSERT(it != installed.end());
+ }
+
+ modules->install("httpd", "2.4", "default");
+ {
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ CPPUNIT_ASSERT(installed.size() == 2);
+ }
+
+ modules->save();
+
+ modules->uninstall("httpd", "2.4", "default");
+ {
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ auto it = std::find(installed.begin(), installed.end(), "default");
+ CPPUNIT_ASSERT(it == installed.end());
+ auto removed = modules->getRemovedProfiles()["httpd"];
+ it = std::find(removed.begin(), removed.end(), "default");
+ CPPUNIT_ASSERT(it != removed.end());
+ }
+
+ modules->uninstall("httpd", "2.4", "doc");
+ {
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ auto it = std::find(installed.begin(), installed.end(), "doc");
+ CPPUNIT_ASSERT(it == installed.end());
+ auto removed = modules->getRemovedProfiles()["httpd"];
+ it = std::find(removed.begin(), removed.end(), "doc");
+ CPPUNIT_ASSERT(it != removed.end());
+ }
+
+ auto installed = modules->getInstalledProfiles()["httpd"];
+ CPPUNIT_ASSERT(installed.empty());
+
+ modules->save();
+}
--- /dev/null
+#ifndef LIBDNF_MODULEPACKAGECONTAINERTEST_HPP
+#define LIBDNF_MODULEPACKAGECONTAINERTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/module/ModulePackageContainer.hpp"
+#include "libdnf/dnf-context.hpp"
+
+class ModulePackageContainerTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ModulePackageContainerTest);
+ CPPUNIT_TEST(testEnabledModules);
+ CPPUNIT_TEST(testDisableEnableModules);
+ CPPUNIT_TEST(testRollback);
+ CPPUNIT_TEST(testInstallRemoveProfile);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testEnabledModules();
+ void testDisableEnableModules();
+ void testRollback();
+ void testInstallRemoveProfile();
+
+private:
+ DnfContext *context;
+ libdnf::ModulePackageContainer *modules;
+ char* tmpdir;
+};
+
+#endif /* LIBDNF_MODULEPACKAGECONTAINERTEST_HPP */
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModuleProfileTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackageTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModuleProfileTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ModulePackageTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include "ModulePackageTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ModulePackageTest);
+
+#include "libdnf/log.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+
+#include <algorithm>
+
+void ModulePackageTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+
+ dnf_context_set_config_file_path("");
+ context = dnf_context_new();
+ dnf_context_set_release_ver(context, "26");
+ dnf_context_set_arch(context, "x86_64");
+ dnf_context_set_platform_module(context, "platform:26");
+ dnf_context_set_install_root(context, TESTDATADIR "/modules/");
+ g_autoptr(DnfLock) lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+ dnf_context_set_repo_dir(context, TESTDATADIR "/modules/yum.repos.d/");
+ dnf_context_set_solv_dir(context, "/tmp");
+ dnf_context_setup(context, nullptr, &error);
+ g_assert_no_error(error);
+
+ DnfState *state = dnf_context_get_state(context);
+ dnf_context_setup_sack(context, state, &error);
+ g_assert_no_error(error);
+
+ auto sack = dnf_context_get_sack(context);
+ libdnf::ModulePackageContainer *modules = dnf_sack_get_module_container(sack);
+ packages = modules->getModulePackages();
+}
+
+void ModulePackageTest::tearDown()
+{
+ g_object_unref(context);
+}
+
+void ModulePackageTest::testSimpleGetters()
+{
+ CPPUNIT_ASSERT(packages[0]->getName() == "base-runtime");
+ CPPUNIT_ASSERT(!strcmp(packages[0]->getNameCStr(), "base-runtime"));
+
+ CPPUNIT_ASSERT(packages[0]->getStream() == "f26");
+ CPPUNIT_ASSERT(!strcmp(packages[0]->getStreamCStr(), "f26"));
+
+ CPPUNIT_ASSERT(packages[0]->getNameStream() == "base-runtime:f26");
+ CPPUNIT_ASSERT(packages[0]->getNameStreamVersion() == "base-runtime:f26:1");
+
+ CPPUNIT_ASSERT(packages[0]->getRepoID() == "test");
+
+ CPPUNIT_ASSERT(packages[0]->getVersion() == "1");
+ CPPUNIT_ASSERT(packages[0]->getVersionNum() == 1);
+
+ CPPUNIT_ASSERT(packages[0]->getContext() == "e3b0c442");
+ CPPUNIT_ASSERT(!strcmp(packages[0]->getContextCStr(), "e3b0c442"));
+
+ CPPUNIT_ASSERT(packages[0]->getArch() == "x86_64");
+ CPPUNIT_ASSERT(!strcmp(packages[0]->getArchCStr(), "x86_64"));
+
+ CPPUNIT_ASSERT(packages[0]->getFullIdentifier() == "base-runtime:f26:1:e3b0c442:x86_64");
+
+ CPPUNIT_ASSERT(packages[0]->getSummary() == "Fake module");
+ CPPUNIT_ASSERT(packages[0]->getDescription() == "Fake module");
+
+}
+
+void ModulePackageTest::testGetArtifacts()
+{
+ std::vector<std::string> rpms = packages[0]->getArtifacts();
+
+ CPPUNIT_ASSERT(rpms.size() == 12);
+ CPPUNIT_ASSERT(rpms[0] == "basesystem-0:11-3.noarch");
+ CPPUNIT_ASSERT(rpms[2] == "bash-doc-0:4.4.12-2.noarch");
+ CPPUNIT_ASSERT(rpms[11] == "systemd-0:233-3.x86_64");
+}
+
+void ModulePackageTest::testGetProfiles()
+{
+ std::vector<libdnf::ModuleProfile> profiles = packages[0]->getProfiles();
+
+ CPPUNIT_ASSERT(profiles.size() == 2);
+ CPPUNIT_ASSERT(profiles[0].getName() == "default");
+ CPPUNIT_ASSERT(profiles[1].getName() == "minimal");
+
+ profiles = packages[0]->getProfiles("minimal");
+ CPPUNIT_ASSERT(profiles.size() == 1);
+ CPPUNIT_ASSERT(profiles[0].getName() == "minimal");
+
+ profiles = packages[0]->getProfiles("mini*");
+ CPPUNIT_ASSERT(profiles.size() == 1);
+ CPPUNIT_ASSERT(profiles[0].getName() == "minimal");
+}
+
+void ModulePackageTest::testGetModuleDependencies()
+{
+ std::vector<libdnf::ModuleDependencies> deps = packages[0]->getModuleDependencies();
+
+ CPPUNIT_ASSERT(deps.size() == 0);
+
+ deps = packages[3]->getModuleDependencies();
+ CPPUNIT_ASSERT(deps.size() == 1);
+
+ std::vector <std::map<std::string, std::vector<std::string>>> reqs = deps[0].getRequires();
+ CPPUNIT_ASSERT(reqs.size() == 1);
+ std::map<std::string, std::vector<std::string>> map = reqs[0];
+
+ CPPUNIT_ASSERT(map.size() == 1);
+ std::vector<std::string> base_runtime_reqs = map["base-runtime"];
+ CPPUNIT_ASSERT(base_runtime_reqs.size() == 0);
+
+ deps = packages[4]->getModuleDependencies();
+ CPPUNIT_ASSERT(deps.size() == 1);
+
+ reqs = deps[0].getRequires();
+ CPPUNIT_ASSERT(reqs.size() == 1);
+ map = reqs[0];
+
+ CPPUNIT_ASSERT(map.size() == 1);
+ base_runtime_reqs = map["base-runtime"];
+ CPPUNIT_ASSERT(base_runtime_reqs.size() == 1);
+ CPPUNIT_ASSERT(base_runtime_reqs[0] == "f26");
+}
--- /dev/null
+#ifndef LIBDNF_MODULEPACKAGETEST_HPP
+#define LIBDNF_MODULEPACKAGETEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/module/ModulePackageContainer.hpp"
+#include "libdnf/module/ModulePackage.hpp"
+#include "libdnf/dnf-context.hpp"
+
+class ModulePackageTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ModulePackageTest);
+ CPPUNIT_TEST(testSimpleGetters);
+ CPPUNIT_TEST(testGetArtifacts);
+ CPPUNIT_TEST(testGetProfiles);
+ CPPUNIT_TEST(testGetModuleDependencies);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testSimpleGetters();
+ void testGetArtifacts();
+ void testGetProfiles();
+ void testGetModuleDependencies();
+
+private:
+ DnfContext * context{nullptr};
+ std::vector<libdnf::ModulePackage *> packages;
+};
+
+#endif /* LIBDNF_MODULEPACKAGETEST_HPP */
--- /dev/null
+#include "ModuleProfileTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ModuleProfileTest);
+
+#include "libdnf/log.hpp"
+#include "libdnf/dnf-sack-private.hpp"
+
+#include <algorithm>
+
+void ModuleProfileTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+
+ dnf_context_set_config_file_path("");
+ context = dnf_context_new();
+ dnf_context_set_release_ver(context, "26");
+ dnf_context_set_arch(context, "x86_64");
+ dnf_context_set_platform_module(context, "platform:26");
+ dnf_context_set_install_root(context, TESTDATADIR "/modules/");
+ g_autoptr(DnfLock) lock = dnf_lock_new();
+ dnf_lock_set_lock_dir(lock, "/tmp");
+ dnf_context_set_repo_dir(context, TESTDATADIR "/modules/yum.repos.d/");
+ dnf_context_set_solv_dir(context, "/tmp");
+ dnf_context_setup(context, nullptr, &error);
+ g_assert_no_error(error);
+
+ DnfState *state = dnf_context_get_state(context);
+ dnf_context_setup_sack(context, state, &error);
+ g_assert_no_error(error);
+
+ auto sack = dnf_context_get_sack(context);
+ libdnf::ModulePackageContainer *modules = dnf_sack_get_module_container(sack);
+ std::vector<libdnf::ModulePackage *> packages = modules->getModulePackages();
+ profiles = packages[0]->getProfiles();
+}
+
+void ModuleProfileTest::tearDown()
+{
+ g_object_unref(context);
+}
+
+void ModuleProfileTest::testGetName()
+{
+ CPPUNIT_ASSERT((profiles[0].getName() == "default"));
+ CPPUNIT_ASSERT((profiles[1].getName() == "minimal"));
+}
+
+void ModuleProfileTest::testGetDescription()
+{
+ CPPUNIT_ASSERT((profiles[0].getDescription() == ""));
+ CPPUNIT_ASSERT((profiles[1].getDescription() == ""));
+}
+
+void ModuleProfileTest::testGetContent()
+{
+ std::vector<std::string> content = profiles[0].getContent();
+ CPPUNIT_ASSERT(content.size() == 4);
+ CPPUNIT_ASSERT(content[0] == "bash");
+ CPPUNIT_ASSERT(content[1] == "glibc");
+ CPPUNIT_ASSERT(content[2] == "kernel");
+ CPPUNIT_ASSERT(content[3] == "systemd");
+
+ content = profiles[1].getContent();
+ CPPUNIT_ASSERT(content.size() == 1);
+ CPPUNIT_ASSERT(content[0] == "glibc");
+}
--- /dev/null
+#ifndef LIBDNF_MODULEPROFILETEST_HPP
+#define LIBDNF_MODULEPROFILETEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/module/modulemd/ModuleProfile.hpp"
+#include "libdnf/module/ModulePackageContainer.hpp"
+
+class ModuleProfileTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(ModuleProfileTest);
+ CPPUNIT_TEST(testGetName);
+ CPPUNIT_TEST(testGetDescription);
+ CPPUNIT_TEST(testGetContent);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testGetName();
+ void testGetDescription();
+ void testGetContent();
+
+private:
+ DnfContext * context{nullptr};
+ std::vector<libdnf::ModuleProfile> profiles;
+};
+
+#endif /* LIBDNF_MODULEPROFILETEST_HPP */
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/PackageTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/PackageInstantiable.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencyTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencyContainerTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/PackageTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencyTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DependencyContainerTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include <solv/pool.h>
+#include "libdnf/repo/solvable/Dependency.hpp"
+#include "DependencyContainerTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DependencyContainerTest);
+
+void DependencyContainerTest::setUp()
+{
+ sack = dnf_sack_new();
+ container = std::unique_ptr<libdnf::DependencyContainer>(new libdnf::DependencyContainer(sack));
+}
+
+void DependencyContainerTest::tearDown()
+{
+ g_object_unref(sack);
+}
+
+void DependencyContainerTest::testAdd()
+{
+ auto dependency = new libdnf::Dependency(sack, "foo", "1.0", DNF_COMPARISON_EQ);
+
+ container->add(dependency);
+ libdnf::Dependency *actual = container->getPtr(0);
+
+ CPPUNIT_ASSERT(strcmp(dependency->toString(), actual->toString()) == 0);
+ delete actual;
+ delete dependency;
+}
+
+void DependencyContainerTest::testExtend()
+{
+ auto otherContainer = new libdnf::DependencyContainer(sack);
+ auto dependency = new libdnf::Dependency(sack, "foo", "1.0", DNF_COMPARISON_EQ);
+ auto otherDependency = new libdnf::Dependency(sack, "bar", "1.1", DNF_COMPARISON_EQ);
+
+ container->add(dependency);
+ CPPUNIT_ASSERT_EQUAL(1, container->count());
+
+ otherContainer->add(otherDependency);
+ CPPUNIT_ASSERT_EQUAL(1, otherContainer->count());
+
+ container->extend(otherContainer);
+ libdnf::Dependency *actual = container->getPtr(0);
+ CPPUNIT_ASSERT(strcmp(otherDependency->toString(), actual->toString()) == 0);
+
+ delete otherContainer;
+ delete dependency;
+ delete otherDependency;
+ delete actual;
+}
+
+void DependencyContainerTest::testGet()
+{
+ auto dependency = new libdnf::Dependency(sack, "foo", "1.0", DNF_COMPARISON_EQ);
+ auto otherDependency = new libdnf::Dependency(sack, "bar", "1.1", DNF_COMPARISON_EQ);
+
+ container->add(dependency);
+ container->add(otherDependency);
+
+ libdnf::Dependency *actual = container->getPtr(0);
+ CPPUNIT_ASSERT(strcmp(dependency->toString(), actual->toString()) == 0);
+ delete actual;
+
+ actual = container->getPtr(1);
+ CPPUNIT_ASSERT(strcmp(otherDependency->toString(), actual->toString()) == 0);
+
+ delete dependency;
+ delete otherDependency;
+ delete actual;
+}
+
+void DependencyContainerTest::testCount()
+{
+ auto otherContainer = new libdnf::DependencyContainer(sack);
+ auto dependency = new libdnf::Dependency(sack, "foo", "1.0", DNF_COMPARISON_EQ);
+
+ CPPUNIT_ASSERT_EQUAL(0, container->count());
+ container->add(dependency);
+ CPPUNIT_ASSERT_EQUAL(1, container->count());
+
+ otherContainer->add(dependency);
+ CPPUNIT_ASSERT_EQUAL(1, otherContainer->count());
+
+ container->extend(otherContainer);
+ CPPUNIT_ASSERT_EQUAL(2, container->count());
+
+ delete otherContainer;
+ delete dependency;
+}
--- /dev/null
+#ifndef LIBDNF_RELATIONALDEPENDENCYCONTAINERTEST_HPP
+#define LIBDNF_RELATIONALDEPENDENCYCONTAINERTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/repo/solvable/DependencyContainer.hpp"
+
+class DependencyContainerTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(DependencyContainerTest);
+ CPPUNIT_TEST(testAdd);
+ CPPUNIT_TEST(testExtend);
+ CPPUNIT_TEST(testGet);
+ CPPUNIT_TEST(testCount);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testAdd();
+ void testExtend();
+ void testGet();
+ void testCount();
+
+private:
+ std::unique_ptr<libdnf::DependencyContainer> container;
+ DnfSack *sack;
+};
+
+
+#endif //LIBDNF_RELATIONALDEPENDENCYCONTAINERTEST_HPP
--- /dev/null
+#include <solv/pool.h>
+#include <memory>
+#include <solv/repo.h>
+#include <solv/poolarch.h>
+
+#include "DependencyTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DependencyTest);
+
+void DependencyTest::setUp()
+{
+ sack = dnf_sack_new();
+
+ dependency = std::unique_ptr<libdnf::Dependency>(new libdnf::Dependency(sack, "foo = 1.0"));
+}
+
+void DependencyTest::tearDown()
+{
+ g_object_unref(sack);
+}
+
+void DependencyTest::testName()
+{
+ CPPUNIT_ASSERT(strcmp("foo", dependency->getName()) == 0);
+}
+
+void DependencyTest::testVersion()
+{
+ CPPUNIT_ASSERT(strcmp("1.0", dependency->getVersion()) == 0);
+}
+
+void DependencyTest::testParse()
+{
+ std::unique_ptr<libdnf::Dependency> dependency = std::unique_ptr<libdnf::Dependency>(
+ new libdnf::Dependency(sack, "bar"));
+
+ CPPUNIT_ASSERT(strcmp("bar", dependency->getName()) == 0);
+ CPPUNIT_ASSERT(strcmp("", dependency->getVersion()) == 0);
+}
+
+
+
+
--- /dev/null
+#ifndef LIBDNF_SOLVABLEDEPENDENCYTEST_HPP
+#define LIBDNF_SOLVABLEDEPENDENCYTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+
+#include "libdnf/repo/solvable/Dependency.hpp"
+
+class DependencyTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(DependencyTest);
+ CPPUNIT_TEST(testName);
+ CPPUNIT_TEST(testVersion);
+ CPPUNIT_TEST(testParse);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testName();
+ void testVersion();
+ void testParse();
+
+private:
+ std::unique_ptr<libdnf::Dependency> dependency;
+ DnfSack *sack;
+};
+
+
+#endif //LIBDNF_SOLVABLEDEPENDENCYTEST_HPP
--- /dev/null
+#include "PackageInstantiable.hpp"
+
+PackageInstantiable::PackageInstantiable(DnfSack *sack,
+ const HyRepo repo,
+ const char *name,
+ const char *version,
+ const char *arch)
+ : Package(sack, repo, name, version, arch)
+{
+ addProvides(std::make_shared<libdnf::Dependency>(sack, "rpm = 1.0"));
+}
+
+const char *PackageInstantiable::getName() const
+{
+ return getSolvableName();
+}
+
+const char *PackageInstantiable::getVersion() const
+{
+ return getSolvableEvr();
+}
--- /dev/null
+#ifndef LIBDNF_PACKAGETESTABLE_HPP
+#define LIBDNF_PACKAGETESTABLE_HPP
+
+#include "libdnf/repo/solvable/Package.hpp"
+
+class PackageInstantiable : public libdnf::Package
+{
+public:
+ PackageInstantiable(DnfSack *sack, HyRepo repo, const char *name, const char *version, const char *arch);
+
+ virtual const char *getName() const;
+ virtual const char *getVersion() const;
+};
+
+
+#endif //LIBDNF_PACKAGETESTABLE_HPP
--- /dev/null
+#include "PackageTest.hpp"
+
+#include <libdnf/repo/Repo-private.hpp>
+#include <solv/poolarch.h>
+#include <solv/solver.h>
+#include <solv/selection.h>
+
+CPPUNIT_TEST_SUITE_REGISTRATION(PackageTest);
+
+void PackageTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+ sack = dnf_sack_new();
+ repo = hy_repo_create("repo");
+ libdnf::repoGetImpl(repo)->attachLibsolvRepo(repo_create(dnf_sack_get_pool(sack), "repo"));
+ dnf_sack_load_repo(sack, repo, 0, &error);
+ package = std::unique_ptr<PackageInstantiable>(new PackageInstantiable(sack, repo, "rpm", "1.0", "x86_64"));
+}
+
+void PackageTest::tearDown()
+{
+ hy_repo_free(repo);
+ g_object_unref(sack);
+}
+
+void PackageTest::testName()
+{
+ CPPUNIT_ASSERT(strcmp("rpm", package->getName()) == 0);
+}
+
+void PackageTest::testVersion()
+{
+ CPPUNIT_ASSERT(strcmp("1.0", package->getVersion()) == 0);
+}
+
+void PackageTest::testArch()
+{
+ CPPUNIT_ASSERT(strcmp("x86_64", package->getArch()) == 0);
+}
+
+void PackageTest::testIsInRepo()
+{
+ Pool *pool = dnf_sack_get_pool(sack);
+ Repo *repo = libdnf::repoGetImpl(this->repo)->libsolvRepo;
+
+ Solvable *solvable = pool_id2solvable(pool, package->getId());
+
+ std::string name = pool_id2str(pool, solvable->name);
+ std::string version = pool_id2str(pool, solvable->evr);
+ std::string arch = pool_id2str(pool, solvable->arch);
+
+ CPPUNIT_ASSERT("rpm" == name);
+ CPPUNIT_ASSERT("1.0" == version);
+ CPPUNIT_ASSERT("x86_64" == arch);
+
+ Id *provides = repo->idarraydata + solvable->dep_provides;
+ std::string provideName = pool_id2str(pool, *provides);
+ std::string provideRelation = pool_id2rel(pool, *provides);
+ std::string provideEvr = pool_id2evr(pool, *provides);
+ CPPUNIT_ASSERT("rpm" == provideName);
+ CPPUNIT_ASSERT(" = " == provideRelation);
+ CPPUNIT_ASSERT("1.0" == provideEvr);
+}
--- /dev/null
+#ifndef LIBDNF_SOLVABLESTEST_HPP
+#define LIBDNF_SOLVABLESTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+
+#include "PackageInstantiable.hpp"
+
+class PackageTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(PackageTest);
+ CPPUNIT_TEST(testName);
+ CPPUNIT_TEST(testVersion);
+ CPPUNIT_TEST(testArch);
+ CPPUNIT_TEST(testIsInRepo);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testName();
+ void testVersion();
+ void testArch();
+ void testIsInRepo();
+
+private:
+ std::unique_ptr<PackageInstantiable> package;
+ DnfSack *sack;
+ HyRepo repo;
+};
+
+
+#endif //LIBDNF_SOLVABLESTEST_HPP
--- /dev/null
+#include "AdvisoryTest.hpp"
+
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-iutil-private.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AdvisoryTest);
+
+#define UNITTEST_DIR "/tmp/libdnfXXXXXX"
+
+void AdvisoryTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+
+ tmpdir = g_strdup(UNITTEST_DIR);
+ char *retptr = mkdtemp(tmpdir);
+ CPPUNIT_ASSERT(retptr);
+
+ sack = dnf_sack_new();
+ // Cache should not be needed, setting just to be safe
+ dnf_sack_set_cachedir(sack, tmpdir);
+ dnf_sack_set_arch(sack, "x86_64", NULL);
+ dnf_sack_setup(sack, 0, NULL);
+ repo = hy_repo_create("test_advisory_repo");
+ std::string repodata = std::string(TESTDATADIR "/advisories/repodata/");
+ hy_repo_set_string(repo, HY_REPO_MD_FN, (repodata + "repomd.xml").c_str());
+ hy_repo_set_string(repo, HY_REPO_PRIMARY_FN, (repodata + "primary.xml.gz").c_str());
+ hy_repo_set_string(repo, HY_REPO_UPDATEINFO_FN, (repodata + "updateinfo.xml.gz").c_str());
+ hy_repo_set_string(repo, MODULES_FN, (repodata + "modules.yaml.gz").c_str());
+ dnf_sack_load_repo(sack, repo, DNF_SACK_LOAD_FLAG_USE_UPDATEINFO, &error);
+
+ // loads modular data into ModulePackageContainer (No module enabled)
+ dnf_sack_filter_modules_v2(sack, nullptr, nullptr, tmpdir, "platform_id:f33", false, false, false);
+
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master", false));
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23", false));
+ // Modify modular data and make modules active (enabled - "perl-DBI:master", "perl:5.23")
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ HyQuery query = new libdnf::Query(sack);
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+
+ CPPUNIT_ASSERT(advisoryPkgs.size() > 0);
+ advisory = advisoryPkgs[0].getAdvisory();
+ delete query;
+}
+
+void AdvisoryTest::tearDown()
+{
+ dnf_remove_recursive_v2(tmpdir, NULL);
+ delete repo;
+ delete advisory;
+ g_object_unref(sack);
+ g_free(tmpdir);
+}
+
+void AdvisoryTest::testGetName()
+{
+ CPPUNIT_ASSERT(!strcmp(advisory->getName(), "FEDORA-2019-0329090518"));
+}
+
+void AdvisoryTest::testGetKind()
+{
+ CPPUNIT_ASSERT(advisory->getKind() == DNF_ADVISORY_KIND_ENHANCEMENT);
+}
+
+void AdvisoryTest::testGetDescription()
+{
+ CPPUNIT_ASSERT(!strcmp(advisory->getDescription(), "Enhance some stuff"));
+}
+
+void AdvisoryTest::testGetRights()
+{
+ CPPUNIT_ASSERT(!strcmp(advisory->getRights(), "Everyone has them"));
+}
+
+void AdvisoryTest::testGetSeverity()
+{
+ CPPUNIT_ASSERT(!strcmp(advisory->getSeverity(), "none"));
+}
+
+void AdvisoryTest::testGetTitle()
+{
+ CPPUNIT_ASSERT(!strcmp(advisory->getTitle(), "glibc bug fix"));
+}
+
+void AdvisoryTest::testGetPackages()
+{
+ std::vector<libdnf::AdvisoryPkg> pkgsvector;
+ advisory->getPackages(pkgsvector);
+ CPPUNIT_ASSERT(pkgsvector.size() == 4);
+}
+
+void AdvisoryTest::testGetApplicablePackagesModulesSetupNoneEnabled()
+{
+ std::vector<libdnf::AdvisoryPkg> pkgsvector;
+
+ // When module are setup but none are enabled no collections are applicable -> no packages
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ modules->reset("perl", false);
+ modules->reset("perl-DBI", false);
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ advisory->getApplicablePackages(pkgsvector);
+ CPPUNIT_ASSERT(pkgsvector.size() == 0);
+}
+
+void AdvisoryTest::testGetApplicablePackagesOneApplicableCollection()
+{
+ std::vector<libdnf::AdvisoryPkg> pkgsvector;
+
+ // When I keep enabled only perl module I get packages from all collections that contain that module
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ modules->reset("perl-DBI");
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ advisory->getApplicablePackages(pkgsvector);
+ CPPUNIT_ASSERT(pkgsvector.size() == 1);
+ CPPUNIT_ASSERT(!g_strcmp0(pkgsvector[0].getNameString(), "not-present"));
+}
+
+void AdvisoryTest::testGetApplicablePackagesMultipleApplicableCollections()
+{
+ std::vector<libdnf::AdvisoryPkg> pkgsvector;
+
+ // When I enable modules from multiple collections -> I get packages from all applicable collections
+ // Enabled - "perl-DBI:master", "perl:5.23"
+ advisory->getApplicablePackages(pkgsvector);
+ CPPUNIT_ASSERT(pkgsvector.size() == 4);
+ CPPUNIT_ASSERT(!g_strcmp0(pkgsvector[0].getNameString(), "test-perl-DBI"));
+ CPPUNIT_ASSERT(!g_strcmp0(pkgsvector[1].getNameString(), "test-perl-DBI-new-collection-override"));
+ CPPUNIT_ASSERT(!g_strcmp0(pkgsvector[2].getNameString(), "test-perl-DBI"));
+ CPPUNIT_ASSERT(!g_strcmp0(pkgsvector[3].getNameString(), "not-present"));
+}
+
+void AdvisoryTest::testGetModules()
+{
+ std::vector<libdnf::AdvisoryModule> modulesvector;
+ modulesvector = advisory->getModules();
+ CPPUNIT_ASSERT(modulesvector.size() == 4);
+}
+
+void AdvisoryTest::testGetReferences()
+{
+ std::vector<libdnf::AdvisoryRef> refsvector;
+ advisory->getReferences(refsvector);
+ CPPUNIT_ASSERT(refsvector.size() == 2);
+}
--- /dev/null
+#ifndef LIBDNF_ADVISORYTEST_HPP
+#define LIBDNF_ADVISORYTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+
+#include <libdnf/sack/advisory.hpp>
+#include <libdnf/sack/advisorymodule.hpp>
+#include <libdnf/sack/query.hpp>
+
+class AdvisoryTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(AdvisoryTest);
+ CPPUNIT_TEST(testGetName);
+ CPPUNIT_TEST(testGetKind);
+ CPPUNIT_TEST(testGetDescription);
+ CPPUNIT_TEST(testGetRights);
+ CPPUNIT_TEST(testGetSeverity);
+ CPPUNIT_TEST(testGetTitle);
+ CPPUNIT_TEST(testGetPackages);
+ CPPUNIT_TEST(testGetApplicablePackagesModulesSetupNoneEnabled);
+ CPPUNIT_TEST(testGetApplicablePackagesOneApplicableCollection);
+ CPPUNIT_TEST(testGetApplicablePackagesMultipleApplicableCollections);
+ CPPUNIT_TEST(testGetModules);
+ CPPUNIT_TEST(testGetReferences);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testGetName();
+ void testGetKind();
+ void testGetDescription();
+ void testGetRights();
+ void testGetSeverity();
+ void testGetTitle();
+ void testGetPackages();
+ void testGetApplicablePackagesModulesSetupNoneEnabled();
+ void testGetApplicablePackagesOneApplicableCollection();
+ void testGetApplicablePackagesMultipleApplicableCollections();
+ void testGetModules();
+ void testGetReferences();
+
+private:
+ DnfContext *context = nullptr;
+ DnfSack *sack = nullptr;
+ HyRepo repo = nullptr;
+ libdnf::Advisory *advisory = nullptr;
+ char* tmpdir = nullptr;
+};
+
+
+#endif //LIBDNF_ADVISORYTEST_HPP
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/AdvisoryTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/QueryTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DnfPackageTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/AdvisoryTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/QueryTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/DnfPackageTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include "DnfPackageTest.hpp"
+
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-iutil-private.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DnfPackageTest);
+
+#define UNITTEST_DIR "/tmp/libdnfXXXXXX"
+
+void DnfPackageTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+
+ tmpdir = g_strdup(UNITTEST_DIR);
+ char *retptr = mkdtemp(tmpdir);
+ CPPUNIT_ASSERT(retptr);
+
+ sack = dnf_sack_new();
+ // Cache should not be needed, setting just to be safe
+ dnf_sack_set_cachedir(sack, tmpdir);
+ dnf_sack_set_arch(sack, "x86_64", NULL);
+ dnf_sack_setup(sack, 0, NULL);
+ repo = hy_repo_create("test_advisory_repo");
+ std::string repodata = std::string(TESTDATADIR "/advisories/repodata/");
+ hy_repo_set_string(repo, HY_REPO_MD_FN, (repodata + "repomd.xml").c_str());
+ hy_repo_set_string(repo, HY_REPO_PRIMARY_FN, (repodata + "primary.xml.gz").c_str());
+ hy_repo_set_string(repo, HY_REPO_UPDATEINFO_FN, (repodata + "updateinfo.xml.gz").c_str());
+ hy_repo_set_string(repo, MODULES_FN, (repodata + "modules.yaml.gz").c_str());
+ dnf_sack_load_repo(sack, repo, DNF_SACK_LOAD_FLAG_USE_UPDATEINFO, &error);
+
+ // loads modular data into ModulePackageContainer (No module enabled)
+ dnf_sack_filter_modules_v2(sack, nullptr, nullptr, tmpdir, "platform_id:f33", false, false, false);
+
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master", false));
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23", false));
+ // Modify modular data and make modules active (enabled - "perl-DBI:master", "perl:5.23")
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ HyQuery query = new libdnf::Query(sack);
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+
+ CPPUNIT_ASSERT(advisoryPkgs.size() > 0);
+
+ delete query;
+}
+
+void DnfPackageTest::tearDown()
+{
+ dnf_remove_recursive_v2(tmpdir, NULL);
+ delete repo;
+ g_object_unref(sack);
+ g_free(tmpdir);
+}
+
+void DnfPackageTest::testDnfPackageGetAdvisories()
+{
+ HyQuery query = new libdnf::Query(sack);
+ DnfPackage * p = dnf_package_new(sack, query->getIndexItem(0));
+
+ CPPUNIT_ASSERT(!g_strcmp0(dnf_package_get_nevra(p), "test-perl-DBI-1-2.module_el8+6587+9879afr5.x86_64"));
+
+ GPtrArray *advisories;
+
+ // When modules are not setup all advisory collections are applicable
+ advisories = dnf_package_get_advisories(p, HY_EQ);
+ CPPUNIT_ASSERT(advisories->len == 1);
+
+ // When module are setup but none are enabled all collections are not applicable
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ modules->reset("perl", false);
+ modules->reset("perl-DBI", false);
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ // When module are setup but none are enabled all collections are not applicable
+ advisories = dnf_package_get_advisories(p, HY_EQ);
+ CPPUNIT_ASSERT(advisories->len == 0);
+
+ // When I enable module from collection that doesn't contain p package I don't get the advisory
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23", false));
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ advisories = dnf_package_get_advisories(p, HY_EQ);
+ CPPUNIT_ASSERT(advisories->len == 0);
+
+ // When I enable module from collection that contains p package I get the advisory
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master", false));
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ advisories = dnf_package_get_advisories(p, HY_EQ);
+ CPPUNIT_ASSERT(advisories->len == 1);
+
+ delete query;
+}
+
--- /dev/null
+#ifndef LIBDNF_DNFPACKAGETEST_HPP
+#define LIBDNF_DNFPACKAGETEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+
+#include <libdnf/sack/query.hpp>
+#include <libdnf/sack/advisory.hpp>
+
+class DnfPackageTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(DnfPackageTest);
+ CPPUNIT_TEST(testDnfPackageGetAdvisories);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testDnfPackageGetAdvisories();
+
+private:
+ DnfSack *sack = nullptr;
+ HyRepo repo = nullptr;
+ char* tmpdir = nullptr;
+};
+
+
+#endif //LIBDNF_DNFPACKAGETEST_HPP
--- /dev/null
+#include "QueryTest.hpp"
+
+#include "libdnf/dnf-sack-private.hpp"
+#include "libdnf/hy-iutil-private.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(QueryTest);
+
+#define UNITTEST_DIR "/tmp/libdnfXXXXXX"
+
+void QueryTest::setUp()
+{
+ g_autoptr(GError) error = nullptr;
+
+ tmpdir = g_strdup(UNITTEST_DIR);
+ char *retptr = mkdtemp(tmpdir);
+ CPPUNIT_ASSERT(retptr);
+
+ sack = dnf_sack_new();
+ // Cache should not be needed, setting just to be safe
+ dnf_sack_set_cachedir(sack, tmpdir);
+ dnf_sack_set_arch(sack, "x86_64", NULL);
+ dnf_sack_setup(sack, 0, NULL);
+ repo = hy_repo_create("test_advisory_repo");
+ std::string repodata = std::string(TESTDATADIR "/advisories/repodata/");
+ hy_repo_set_string(repo, HY_REPO_MD_FN, (repodata + "repomd.xml").c_str());
+ hy_repo_set_string(repo, HY_REPO_PRIMARY_FN, (repodata + "primary.xml.gz").c_str());
+ hy_repo_set_string(repo, HY_REPO_UPDATEINFO_FN, (repodata + "updateinfo.xml.gz").c_str());
+ hy_repo_set_string(repo, MODULES_FN, (repodata + "modules.yaml.gz").c_str());
+ dnf_sack_load_repo(sack, repo, DNF_SACK_LOAD_FLAG_USE_UPDATEINFO, &error);
+
+ // loads modular data into ModulePackageContainer (No module enabled)
+ dnf_sack_filter_modules_v2(sack, nullptr, nullptr, tmpdir, "platform_id:f33", false, false, false);
+
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master", false));
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23", false));
+ // Modify modular data and make modules active (enabled - "perl-DBI:master", "perl:5.23")
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ HyQuery query = new libdnf::Query(sack);
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+
+ CPPUNIT_ASSERT(advisoryPkgs.size() > 0);
+
+ delete query;
+}
+
+void QueryTest::tearDown()
+{
+ dnf_remove_recursive_v2(tmpdir, NULL);
+ delete repo;
+ g_object_unref(sack);
+ g_free(tmpdir);
+}
+
+void QueryTest::testQueryGetAdvisoryPkgs()
+{
+ HyQuery query = new libdnf::Query(sack);
+ std::vector<libdnf::AdvisoryPkg> advisoryPkgs;
+
+ // Starting with perl and perl-DBI enabled
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+ CPPUNIT_ASSERT(advisoryPkgs.size() == 2);
+ // We get test-perl-DBI twice because its in two collections
+ CPPUNIT_ASSERT(!g_strcmp0(advisoryPkgs[0].getNameString(), "test-perl-DBI"));
+ CPPUNIT_ASSERT(!g_strcmp0(advisoryPkgs[1].getNameString(), "test-perl-DBI"));
+
+ // When modules are setup but none are enabled all collections are not applicable - no enabled module
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ modules->reset("perl", false);
+ modules->reset("perl-DBI", false);
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ advisoryPkgs.clear();
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+ CPPUNIT_ASSERT(advisoryPkgs.size() == 0);
+
+ // When I enable module from collection that contains non present pkg it doesn't show up
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23", false));
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ advisoryPkgs.clear();
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+ CPPUNIT_ASSERT(advisoryPkgs.size() == 0);
+
+ // When I enable a module with multiple collections I will receave advisory packages only for active context
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master", false));
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+
+ advisoryPkgs.clear();
+ query->getAdvisoryPkgs(HY_EQ, advisoryPkgs);
+ CPPUNIT_ASSERT(advisoryPkgs.size() == 2);
+ CPPUNIT_ASSERT(!g_strcmp0(advisoryPkgs[0].getNameString(), "test-perl-DBI"));
+ CPPUNIT_ASSERT(!g_strcmp0(advisoryPkgs[1].getNameString(), "test-perl-DBI"));
+
+ delete query;
+}
+
+void QueryTest::testQueryFilterAdvisory()
+{
+ // Starting with perl and perl-DBI enabled
+ HyQuery query = new libdnf::Query(sack);
+ query->addFilter(HY_PKG_ADVISORY_TYPE, HY_EQ, "enhancement");
+ CPPUNIT_ASSERT(query->size() == 2);
+
+ // We get test-perl-DBI twice because its in two collections
+ libdnf::PackageSet pset = *(query->getResultPset());
+ DnfPackage *pkg = dnf_package_new(sack, pset[0]);
+ CPPUNIT_ASSERT(!g_strcmp0(dnf_package_get_name(pkg), "test-perl-DBI"));
+ g_object_unref(pkg);
+ pkg = dnf_package_new(sack, pset[1]);
+ CPPUNIT_ASSERT(!g_strcmp0(dnf_package_get_name(pkg), "test-perl-DBI"));
+ g_object_unref(pkg);
+ delete query;
+
+ // When module are setup but none are enabled all collections are not applicable - no enabled module
+ libdnf::ModulePackageContainer * modules = dnf_sack_get_module_container(sack);
+ modules->reset("perl", false);
+ modules->reset("perl-DBI", false);
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ query = new libdnf::Query(sack);
+ query->addFilter(HY_PKG_ADVISORY_TYPE, HY_EQ, "enhancement");
+ CPPUNIT_ASSERT(query->size() == 0);
+ delete query;
+
+ // When I enable module from collection that contains non present pkg it doesn't show up
+ CPPUNIT_ASSERT(modules->enable("perl", "5.23"));
+ modules->save();
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ query = new libdnf::Query(sack);
+ query->addFilter(HY_PKG_ADVISORY_TYPE, HY_EQ, "enhancement");
+ CPPUNIT_ASSERT(query->size() == 0);
+ delete query;
+
+ // When I enable a module from multiple collections that contain a present package I get them
+ CPPUNIT_ASSERT(modules->enable("perl-DBI", "master"));
+ modules->save();
+ dnf_sack_filter_modules_v2(sack, modules, nullptr, tmpdir, nullptr, true, false, false);
+ query = new libdnf::Query(sack);
+ query->addFilter(HY_PKG_ADVISORY_TYPE, HY_EQ, "enhancement");
+ CPPUNIT_ASSERT(query->size() == 2);
+ libdnf::PackageSet pset2 = *(query->getResultPset());
+ pkg = dnf_package_new(sack, pset2[0]);
+ CPPUNIT_ASSERT(!g_strcmp0(dnf_package_get_name(pkg), "test-perl-DBI"));
+ g_object_unref(pkg);
+ pkg = dnf_package_new(sack, pset2[1]);
+ CPPUNIT_ASSERT(!g_strcmp0(dnf_package_get_name(pkg), "test-perl-DBI"));
+ g_object_unref(pkg);
+ delete query;
+}
--- /dev/null
+#ifndef LIBDNF_QUERYTEST_HPP
+#define LIBDNF_QUERYTEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <memory>
+
+#include <libdnf/sack/query.hpp>
+#include <libdnf/sack/advisory.hpp>
+
+class QueryTest : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(QueryTest);
+ CPPUNIT_TEST(testQueryGetAdvisoryPkgs);
+ CPPUNIT_TEST(testQueryFilterAdvisory);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testQueryGetAdvisoryPkgs();
+ void testQueryFilterAdvisory();
+
+private:
+ DnfSack *sack = nullptr;
+ HyRepo repo = nullptr;
+ char* tmpdir = nullptr;
+};
+
+
+#endif //LIBDNF_QUERYTEST_HPP
--- /dev/null
+set(LIBDNF_TEST_SOURCES
+ ${LIBDNF_TEST_SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsEnvironmentItemTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsGroupItemTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/RpmItemTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionItemReasonTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/WorkflowTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransformerTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/MergedTransactionTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/MigrationTest.cpp
+ PARENT_SCOPE
+)
+
+set(LIBDNF_TEST_HEADERS
+ ${LIBDNF_TEST_HEADERS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsEnvironmentItemTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/CompsGroupItemTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/RpmItemTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionItemReasonTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransactionTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/WorkflowTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/TransformerTest.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/MigrationTest.hpp
+ PARENT_SCOPE
+)
--- /dev/null
+#include <chrono>
+#include <cstdio>
+#include <iostream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/CompsEnvironmentItem.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "CompsEnvironmentItemTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CompsEnvironmentItemTest);
+
+using namespace libdnf;
+
+void
+CompsEnvironmentItemTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+CompsEnvironmentItemTest::tearDown()
+{
+}
+
+static std::shared_ptr< CompsEnvironmentItem >
+createCompsEnvironment(std::shared_ptr< SQLite3 > conn)
+{
+ auto env = std::make_shared< CompsEnvironmentItem >(conn);
+ env->setEnvironmentId("minimal");
+ env->setName("Minimal Environment");
+ env->setTranslatedName("translated(Minimal Environment)");
+ env->setPackageTypes(CompsPackageType::DEFAULT);
+ env->addGroup("core", true, CompsPackageType::MANDATORY);
+ env->addGroup("base", false, CompsPackageType::OPTIONAL);
+ env->save();
+ return env;
+}
+
+void
+CompsEnvironmentItemTest::testCreate()
+{
+ auto env = createCompsEnvironment(conn);
+
+ CompsEnvironmentItem env2(conn, env->getId());
+ CPPUNIT_ASSERT(env2.getId() == env->getId());
+ CPPUNIT_ASSERT(env2.getEnvironmentId() == env->getEnvironmentId());
+ CPPUNIT_ASSERT(env2.getName() == env->getName());
+ CPPUNIT_ASSERT(env2.getTranslatedName() == env->getTranslatedName());
+ CPPUNIT_ASSERT(env2.getPackageTypes() == env->getPackageTypes());
+
+ {
+ auto group = env2.getGroups().at(0);
+ CPPUNIT_ASSERT(group->getGroupId() == "base");
+ CPPUNIT_ASSERT(group->getInstalled() == false);
+ CPPUNIT_ASSERT(group->getGroupType() == CompsPackageType::OPTIONAL);
+ }
+ {
+ auto group = env2.getGroups().at(1);
+ CPPUNIT_ASSERT(group->getGroupId() == "core");
+ CPPUNIT_ASSERT(group->getInstalled() == true);
+ CPPUNIT_ASSERT(group->getGroupType() == CompsPackageType::MANDATORY);
+ }
+
+ // test adding a duplicate group
+ env2.addGroup("base", true, CompsPackageType::MANDATORY);
+ {
+ auto group = env2.getGroups().at(0);
+ CPPUNIT_ASSERT(group->getGroupId() == "base");
+ CPPUNIT_ASSERT(group->getInstalled() == true);
+ CPPUNIT_ASSERT(group->getGroupType() == CompsPackageType::MANDATORY);
+ }
+}
+
+void
+CompsEnvironmentItemTest::testGetTransactionItems()
+{
+ libdnf::swdb_private::Transaction trans(conn);
+ auto env = createCompsEnvironment(conn);
+ auto ti = trans.addItem(env, "", TransactionItemAction::INSTALL, TransactionItemReason::USER);
+ ti->setState(TransactionItemState::DONE);
+ trans.begin();
+ trans.finish(TransactionState::DONE);
+
+ libdnf::Transaction trans2(conn, trans.getId());
+
+ auto transItems = trans2.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, static_cast< int >(transItems.size()));
+
+ auto transItem = transItems.at(0);
+
+ auto env2 = transItem->getCompsEnvironmentItem();
+ {
+ auto group = env2->getGroups().at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("base"), group->getGroupId());
+ }
+ {
+ auto group = env2->getGroups().at(1);
+ CPPUNIT_ASSERT_EQUAL(std::string("core"), group->getGroupId());
+ }
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
+#define LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class CompsEnvironmentItemTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(CompsEnvironmentItemTest);
+ CPPUNIT_TEST(testCreate);
+ CPPUNIT_TEST(testGetTransactionItems);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testCreate();
+ void testGetTransactionItems();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
--- /dev/null
+#include <chrono>
+#include <cstdio>
+#include <iostream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/CompsGroupItem.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "CompsGroupItemTest.hpp"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CompsGroupItemTest);
+
+using namespace libdnf;
+
+void
+CompsGroupItemTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+CompsGroupItemTest::tearDown()
+{
+}
+
+static std::shared_ptr< CompsGroupItem >
+createCompsGroup(std::shared_ptr< SQLite3 > conn)
+{
+ auto grp = std::make_shared< CompsGroupItem >(conn);
+ grp->setGroupId("core");
+ grp->setName("Smallest possible installation");
+ grp->setTranslatedName("translated(Smallest possible installation)");
+ grp->setPackageTypes(CompsPackageType::DEFAULT);
+ grp->addPackage("bash", true, CompsPackageType::MANDATORY);
+ grp->addPackage("rpm", false, CompsPackageType::OPTIONAL);
+ grp->save();
+ return grp;
+}
+
+void
+CompsGroupItemTest::testCreate()
+{
+ auto grp = createCompsGroup(conn);
+
+ CompsGroupItem grp2(conn, grp->getId());
+ CPPUNIT_ASSERT(grp2.getId() == grp->getId());
+ CPPUNIT_ASSERT(grp2.getGroupId() == grp->getGroupId());
+ CPPUNIT_ASSERT(grp2.getName() == grp->getName());
+ CPPUNIT_ASSERT(grp2.getTranslatedName() == grp->getTranslatedName());
+ CPPUNIT_ASSERT(grp2.getPackageTypes() == grp->getPackageTypes());
+
+ {
+ auto pkg = grp2.getPackages().at(0);
+ CPPUNIT_ASSERT(pkg->getName() == "bash");
+ CPPUNIT_ASSERT(pkg->getInstalled() == true);
+ CPPUNIT_ASSERT(pkg->getPackageType() == CompsPackageType::MANDATORY);
+ }
+ {
+ auto pkg = grp2.getPackages().at(1);
+ CPPUNIT_ASSERT(pkg->getName() == "rpm");
+ CPPUNIT_ASSERT(pkg->getInstalled() == false);
+ CPPUNIT_ASSERT(pkg->getPackageType() == CompsPackageType::OPTIONAL);
+ }
+
+ // test adding a duplicate group
+ grp2.addPackage("rpm", true, CompsPackageType::MANDATORY);
+ {
+ auto pkg = grp2.getPackages().at(1);
+ CPPUNIT_ASSERT(pkg->getName() == "rpm");
+ CPPUNIT_ASSERT(pkg->getInstalled() == true);
+ CPPUNIT_ASSERT(pkg->getPackageType() == CompsPackageType::MANDATORY);
+ }
+}
+
+void
+CompsGroupItemTest::testGetTransactionItems()
+{
+ libdnf::swdb_private::Transaction trans(conn);
+ auto grp = createCompsGroup(conn);
+ auto ti = trans.addItem(grp, "", TransactionItemAction::INSTALL, TransactionItemReason::USER);
+ ti->setState(TransactionItemState::DONE);
+ trans.begin();
+ trans.finish(TransactionState::DONE);
+
+ libdnf::Transaction trans2(conn, trans.getId());
+
+ auto transItems = trans2.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, static_cast< int >(transItems.size()));
+
+ auto transItem = transItems.at(0);
+
+ auto grp2 = transItem->getCompsGroupItem();
+ {
+ auto pkg = grp2->getPackages().at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("bash"), pkg->getName());
+ }
+ {
+ auto pkg = grp2->getPackages().at(1);
+ CPPUNIT_ASSERT_EQUAL(std::string("rpm"), pkg->getName());
+ }
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
+#define LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class CompsGroupItemTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(CompsGroupItemTest);
+ CPPUNIT_TEST(testCreate);
+ CPPUNIT_TEST(testGetTransactionItems);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testCreate();
+ void testGetTransactionItems();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_COMPSENVIRONMENTITEM_TEST_HPP
--- /dev/null
+#include <set>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/hy-subject.h"
+#include "libdnf/nevra.hpp"
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/MergedTransaction.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "MergedTransactionTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MergedTransactionTest);
+
+void
+MergedTransactionTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+static libdnf::swdb_private::TransactionPtr
+initTransFirst(SQLite3Ptr conn)
+{
+ // create the first transaction
+ auto first = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ first->setDtBegin(1);
+ first->setDtEnd(2);
+ first->setRpmdbVersionBegin("begin 1");
+ first->setRpmdbVersionEnd("end 1");
+ first->setUserId(1000);
+ first->setCmdline("dnf install foo");
+
+ auto dnfRpm = std::make_shared< RPMItem >(conn);
+ dnfRpm->setName("dnf");
+ dnfRpm->setEpoch(0);
+ dnfRpm->setVersion("3.0.0");
+ dnfRpm->setRelease("2.fc26");
+ dnfRpm->setArch("x86_64");
+ dnfRpm->save();
+
+ first->addSoftwarePerformedWith(dnfRpm);
+ return first;
+}
+
+static libdnf::swdb_private::TransactionPtr
+initTransSecond(SQLite3Ptr conn)
+{
+ // create the second transaction
+ auto second = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ second->setDtBegin(3);
+ second->setDtEnd(4);
+ second->setRpmdbVersionBegin("begin 2");
+ second->setRpmdbVersionEnd("end 2");
+ second->setUserId(1001);
+ second->setCmdline("dnf install bar");
+
+ auto rpmRpm = std::make_shared< RPMItem >(conn);
+ rpmRpm->setName("rpm");
+ rpmRpm->setEpoch(0);
+ rpmRpm->setVersion("4.14.0");
+ rpmRpm->setRelease("2.fc26");
+ rpmRpm->setArch("x86_64");
+ rpmRpm->save();
+
+ second->addSoftwarePerformedWith(rpmRpm);
+ return second;
+}
+
+void
+MergedTransactionTest::tearDown()
+{
+}
+
+void
+MergedTransactionTest::testMerge()
+{
+ auto first = initTransFirst(conn);
+ first->begin();
+ first->addConsoleOutputLine(1, "Foo");
+ first->finish(TransactionState::DONE);
+
+ auto second = initTransSecond(conn);
+ second->begin();
+ second->addConsoleOutputLine(1, "Bar");
+ second->finish(TransactionState::ERROR);
+
+ MergedTransaction merged(first);
+ merged.merge(second);
+
+ CPPUNIT_ASSERT_EQUAL((int64_t)1, merged.listIds().at(0));
+ CPPUNIT_ASSERT_EQUAL((int64_t)2, merged.listIds().at(1));
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t)1000, merged.listUserIds().at(0));
+ CPPUNIT_ASSERT_EQUAL((uint32_t)1001, merged.listUserIds().at(1));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("dnf install foo"), merged.listCmdlines().at(0));
+ CPPUNIT_ASSERT_EQUAL(std::string("dnf install bar"), merged.listCmdlines().at(1));
+
+ CPPUNIT_ASSERT_EQUAL(TransactionState::DONE, merged.listStates().at(0));
+ CPPUNIT_ASSERT_EQUAL(TransactionState::ERROR, merged.listStates().at(1));
+
+ CPPUNIT_ASSERT_EQUAL((int64_t)1, merged.getDtBegin());
+ CPPUNIT_ASSERT_EQUAL((int64_t)4, merged.getDtEnd());
+
+ CPPUNIT_ASSERT_EQUAL(std::string("begin 1"), merged.getRpmdbVersionBegin());
+ CPPUNIT_ASSERT_EQUAL(std::string("end 2"), merged.getRpmdbVersionEnd());
+
+ auto output = merged.getConsoleOutput();
+ CPPUNIT_ASSERT_EQUAL(1, output.at(0).first);
+ CPPUNIT_ASSERT_EQUAL(std::string("Foo"), output.at(0).second);
+
+ CPPUNIT_ASSERT_EQUAL(1, output.at(1).first);
+ CPPUNIT_ASSERT_EQUAL(std::string("Bar"), output.at(1).second);
+
+ auto software = merged.getSoftwarePerformedWith();
+ std::set< std::string > names = {"rpm", "dnf"};
+
+ CPPUNIT_ASSERT(names.size() == 2);
+
+ for (auto s : software) {
+ const std::string &name = s->getName();
+ CPPUNIT_ASSERT_MESSAGE("Name: " + name, names.find(name) != names.end());
+ names.erase(name);
+ }
+}
+
+static MergedTransactionPtr
+prepareMergedTransaction(SQLite3Ptr conn,
+ TransactionItemAction actionFirst,
+ TransactionItemAction actionSecond,
+ const std::string &versionFirst,
+ const std::string &versionSecond,
+ TransactionItemAction oldFirstAction = TransactionItemAction::INSTALL,
+ const std::string &oldFirstVersion = {}
+
+)
+{
+ auto firstRPM = std::make_shared< RPMItem >(conn);
+ firstRPM->setName("foo");
+ firstRPM->setEpoch(0);
+ firstRPM->setVersion(versionFirst);
+ firstRPM->setRelease("2.fc26");
+ firstRPM->setArch("x86_64");
+ firstRPM->save();
+
+ auto secondRPM = std::make_shared< RPMItem >(conn);
+ secondRPM->setName("foo");
+ secondRPM->setEpoch(0);
+ secondRPM->setVersion(versionSecond);
+ secondRPM->setRelease("2.fc26");
+ secondRPM->setArch("x86_64");
+ secondRPM->save();
+
+ auto first = initTransFirst(conn);
+ if (oldFirstAction != TransactionItemAction::INSTALL) {
+ auto oldFirst = std::make_shared< RPMItem >(conn);
+ oldFirst->setName("foo");
+ oldFirst->setEpoch(0);
+ oldFirst->setVersion(oldFirstVersion);
+ oldFirst->setRelease("2.fc26");
+ oldFirst->setArch("x86_64");
+ oldFirst->save();
+ first->addItem(oldFirst, "base", oldFirstAction, TransactionItemReason::USER);
+ }
+
+ first->addItem(firstRPM, "base", actionFirst, TransactionItemReason::USER);
+ first->begin();
+ first->finish(TransactionState::DONE);
+
+ auto second = initTransSecond(conn);
+ second->addItem(secondRPM, "base", actionSecond, TransactionItemReason::USER);
+ second->begin();
+ second->finish(TransactionState::DONE);
+
+ auto merged = std::make_shared< MergedTransaction >(first);
+ merged->merge(second);
+ return merged;
+}
+
+/// Erase -> Install = Reinstall
+void
+MergedTransactionTest::testMergeEraseInstallReinstall()
+{
+ auto merged = prepareMergedTransaction(
+ conn, TransactionItemAction::REMOVE, TransactionItemAction::INSTALL, "1.0.0", "1.0.0");
+
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item->getAction());
+}
+
+/// Erase -> Install = Downgrade
+void
+MergedTransactionTest::testMergeEraseInstallDowngrade()
+{
+ auto merged = prepareMergedTransaction(
+ conn, TransactionItemAction::REMOVE, TransactionItemAction::INSTALL, "0.11.0", "0.10.9");
+
+ auto items = merged->getItems();
+
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADE, item->getAction());
+}
+
+/// Erase -> Install = Upgrade
+void
+MergedTransactionTest::testMergeEraseInstallUpgrade()
+{
+ auto merged = prepareMergedTransaction(
+ conn, TransactionItemAction::OBSOLETED, TransactionItemAction::INSTALL, "0.11.0", "0.12.0");
+
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::UPGRADE, item->getAction());
+}
+
+/// Reinstall/Reason change -> (new action) = (new action)
+void
+MergedTransactionTest::testMergeReinstallAny()
+{
+ auto merged = prepareMergedTransaction(conn,
+ TransactionItemAction::REINSTALL,
+ TransactionItemAction::UPGRADE,
+ "1.0.0",
+ "1.0.1",
+ TransactionItemAction::UPGRADED,
+ "0.9.9");
+
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(2, (int)items.size());
+ auto item = items.at(1);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::UPGRADE, item->getAction());
+ auto oldItem = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::UPGRADED, oldItem->getAction());
+}
+
+/// Install -> Erase = (nothing)
+void
+MergedTransactionTest::testMergeInstallErase()
+{
+ auto merged = prepareMergedTransaction(
+ conn, TransactionItemAction::INSTALL, TransactionItemAction::REMOVE, "1.0.0", "1.0.0");
+
+ auto items = merged->getItems();
+
+ // nothing
+ CPPUNIT_ASSERT_EQUAL(0, (int)items.size());
+}
+
+/// Install -> Upgrade/Downgrade = Install (with Upgrade version)
+
+void
+MergedTransactionTest::testMergeInstallAlter()
+{
+ auto merged = prepareMergedTransaction(
+ conn, TransactionItemAction::INSTALL, TransactionItemAction::UPGRADE, "1.0.0", "1.0.1");
+
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction());
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(item->getItem());
+ CPPUNIT_ASSERT_EQUAL(std::string("1.0.1"), rpm->getVersion());
+}
+
+/// Downgrade/Upgrade/Obsoleting -> Reinstall = (old action)
+void
+MergedTransactionTest::testMergeAlterReinstall()
+{
+ auto merged = prepareMergedTransaction(conn,
+ TransactionItemAction::UPGRADE,
+ TransactionItemAction::REINSTALL,
+ "1.0.0",
+ "1.0.0",
+ TransactionItemAction::UPGRADED,
+ "0.9.9");
+
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(2, (int)items.size());
+ auto item = items.at(1);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::UPGRADE, item->getAction());
+ auto oldItem = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::UPGRADED, oldItem->getAction());
+}
+
+/// Downgrade/Upgrade/Obsoleting -> Erase/Obsoleted = Erase/Obsolete (with old package)
+void
+MergedTransactionTest::testMergeAlterErase()
+{
+ auto merged = prepareMergedTransaction(conn,
+ TransactionItemAction::UPGRADE,
+ TransactionItemAction::REMOVE,
+ "1.0.0",
+ "1.0.0",
+ TransactionItemAction::UPGRADED,
+ "0.9.9");
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REMOVE, item->getAction());
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(item->getItem());
+ CPPUNIT_ASSERT_EQUAL(std::string("0.9.9"), rpm->getVersion());
+}
+
+/// Downgrade/Upgrade/Obsoleting -> Downgrade/Upgrade = Downgrade/Upgrade/Reinstall
+void
+MergedTransactionTest::testMergeAlterAlter()
+{
+ auto merged = prepareMergedTransaction(conn,
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemAction::UPGRADE,
+ "1.0.0",
+ "1.0.1",
+ TransactionItemAction::DOWNGRADED,
+ "1.0.1");
+ auto items = merged->getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item->getAction());
+}
+
+
+static RPMItemPtr
+nevraToRPMItem(SQLite3Ptr conn, std::string nevra)
+{
+ libdnf::Nevra nevraObject;
+ if (!nevraObject.parse(nevra.c_str(), HY_FORM_NEVRA)) {
+ return nullptr;
+ }
+ if (nevraObject.getEpoch() < 0) {
+ nevraObject.setEpoch(0);
+ }
+
+ auto rpm = std::make_shared< RPMItem >(conn);
+ rpm->setName(nevraObject.getName());
+ rpm->setEpoch(nevraObject.getEpoch());
+ rpm->setVersion(nevraObject.getVersion());
+ rpm->setRelease(nevraObject.getRelease());
+ rpm->setArch(nevraObject.getArch());
+ return rpm;
+}
+
+/*
+static TransactionPtr
+createTrans(SQLite3Ptr conn, std::string nevra, std::string repoid, TransactionItemAction action, TransactionItemReason reason, std::vector<std::string> obsoletes)
+{
+ Nevra nevraObject;
+ if (!nevraObject.parse(nevra.c_str(), HY_FORM_NEVRA)) {
+ return nullptr;
+ }
+ if (nevraObject.getEpoch() < 0) {
+ nevraObject.setEpoch(0);
+ }
+
+ auto trans = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto rpm = nevraToRPMItem(conn, nevra);
+
+ //std::string repoid = "";
+ //TransactionItemReason reason = TransactionItemReason::USER;
+ auto ti = trans->addItem(rpm, repoid, action, reason);
+ for (auto obs : obsoletes) {
+ //ti->addReplacedBy(obs);
+ }
+ return trans;
+}
+
+static TransactionPtr
+createTrans(SQLite3Ptr conn, std::string nevra, std::string repoid, TransactionItemAction action, TransactionItemReason reason)
+{
+ return createTrans(conn, nevra, repoid, action, reason, {});
+}
+*/
+
+void
+MergedTransactionTest::test_add_remove_installed()
+{
+ /*
+ def test_add_erase_installed(self):
+ """Test add with an erasure of NEVRA which was installed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Install', 'tour-0:4.6-1.noarch', obsoleted_nevras=('lotus-0:3-16.x86_64',))
+ ops.add('Erase', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Erase', 'lotus-0:3-16.x86_64', None, set()),))
+ */
+
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_tour = trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo1",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::DEPENDENCY
+ );
+
+ MergedTransaction merged(trans1);
+ merged.merge(trans2);
+
+ auto items = merged.getItems();
+ //CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+ // TODO
+}
+
+void
+MergedTransactionTest::test_add_remove_removed()
+{
+ return;
+ /*
+ def test_add_erase_removed(self):
+ """Test add with an erasure of NEVRA which was removed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'tour-0:4.6-1.noarch')
+
+ self.assertRaises(
+ ValueError,
+ ops.add, 'Erase', 'tour-0:4.6-1.noarch')
+ */
+
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_tour = trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo1",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::USER
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::DEPENDENCY
+ );
+
+ MergedTransaction merged(trans1);
+ merged.merge(trans2);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+
+ // TODO: different reasons, repos
+}
+
+void
+MergedTransactionTest::test_add_install_installed()
+{
+ return;
+ /*
+ def test_add_install_installed(self):
+ """Test add with two installs of the same NEVRA."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Install', 'tour-0:4.6-1.noarch')
+
+ self.assertRaises(
+ ValueError,
+ ops.add, 'Install', 'tour-0:4.6-1.noarch')
+ */
+
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_tour = trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo1",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::GROUP
+ );
+
+ MergedTransaction merged(trans1);
+ merged.merge(trans2);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+}
+
+void
+MergedTransactionTest::test_add_install_removed()
+{
+ return;
+ /*
+ def test_add_install_removed(self):
+ """Test add with an install of NEVRA which was removed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'tour-0:4.6-1.noarch')
+ ops.add('Install', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Reinstall', 'tour-0:4.6-1.noarch', 'tour-0:4.6-1.noarch', set()),))
+
+ */
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_tour = trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo1",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::DEPENDENCY
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+
+ MergedTransaction merged(trans1);
+ merged.merge(trans2);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
+}
+
+void
+MergedTransactionTest::test_add_obsoleted_installed()
+{
+ return;
+ /*
+ def test_add_obsoleted_installed(self):
+ """Test add with an obsoleted NEVRA which was installed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Install', 'lotus-0:3-16.x86_64')
+ ops.add('Install', 'tour-0:4.6-1.noarch', obsoleted_nevras=('lotus-0:3-16.x86_64',))
+
+ self.assertCountEqual(
+ ops,
+ (('Install', 'tour-0:4.6-1.noarch', None, set()),))
+ */
+
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_lotus = trans1->addItem(
+ nevraToRPMItem(conn, "lotus-0:3-16.x86_64"),
+ "repo1",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::DEPENDENCY
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+ auto trans2_lotus = trans2->addItem(nevraToRPMItem(conn, "lotus-0:3-16.x86_64"), "repo1", TransactionItemAction::OBSOLETED, TransactionItemReason::DEPENDENCY);
+
+ trans2_lotus->addReplacedBy(trans2_tour);
+
+ MergedTransaction merged(trans1);
+ merged.merge(trans2);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
+}
+
+void
+MergedTransactionTest::test_add_obsoleted_obsoleted()
+{
+ return;
+ /*
+ def test_add_obsoleted_obsoleted(self):
+ """Test add with an obsoleted NEVRA which was obsoleted before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add(
+ 'Install',
+ 'tour-0:4.6-1.noarch',
+ obsoleted_nevras=('lotus-0:3-16.x86_64', 'mrkite-0:2-0.x86_64')
+ )
+ ops.add(
+ 'Install',
+ 'pepper-0:20-0.x86_64',
+ obsoleted_nevras=('lotus-0:3-16.x86_64', 'librita-0:1-1.x86_64')
+ )
+
+ self.assertCountEqual(
+ ops,
+ (
+ (
+ 'Install',
+ 'tour-0:4.6-1.noarch',
+ None,
+ {'lotus-0:3-16.x86_64', 'mrkite-0:2-0.x86_64'}
+ ),
+ (
+ 'Install',
+ 'pepper-0:20-0.x86_64',
+ None,
+ {'lotus-0:3-16.x86_64', 'librita-0:1-1.x86_64'}
+ )
+ )
+ )
+ */
+
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans1_tour = trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo1",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::DEPENDENCY
+ );
+
+ /*
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ auto trans2_tour = trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+ auto trans2_lotus = trans2->addItem(nevraToRPMItem(conn, "lotus-0:3-16.x86_64"), "repo1", TransactionItemAction::OBSOLETED, TransactionItemReason::DEPENDENCY);
+
+ trans2_lotus->addReplacedBy(trans2_tour);
+ */
+
+ MergedTransaction merged(trans1);
+ //merged.merge(trans2);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items.size());
+
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item->getRPMItem()->getNEVRA());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::DEPENDENCY, item->getReason());
+}
+
+void
+MergedTransactionTest::test_downgrade()
+{
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemReason::USER
+ );
+ trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::DOWNGRADED,
+ TransactionItemReason::USER
+ );
+
+ MergedTransaction merged(trans1);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(2, (int)items.size());
+
+ {
+ auto item = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADED, item->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
+ }
+
+ {
+ auto item = items.at(1);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADE, item->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item->getReason());
+ }
+
+}
+
+void
+MergedTransactionTest::test_install_downgrade_upgrade_remove()
+{
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::INSTALL,
+ TransactionItemReason::USER
+ );
+
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemReason::USER
+ );
+ trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::DOWNGRADED,
+ TransactionItemReason::USER
+ );
+
+ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans3->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::UPGRADED,
+ TransactionItemReason::USER
+ );
+ trans3->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::UPGRADE,
+ TransactionItemReason::USER
+ );
+
+ auto trans4 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans4->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::USER
+ );
+
+ MergedTransaction merged(trans1);
+
+ // test merging trans1, trans2
+ merged.merge(trans2);
+ auto items2 = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
+ auto item2 = items2.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.6-1.noarch"), item2->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item2->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item2->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
+
+ // test merging trans1, trans2, trans3
+ merged.merge(trans3);
+ auto items3 = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
+ auto item3 = items3.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::INSTALL, item3->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
+
+ // test merging trans1, trans2, trans3, trans4
+ merged.merge(trans4);
+ auto items4 = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(0, (int)items4.size());
+ // trans4 removes the package, empty output is expected
+}
+
+
+void
+MergedTransactionTest::test_downgrade_upgrade_remove()
+{
+ auto trans1 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemReason::USER
+ );
+ trans1->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::DOWNGRADED,
+ TransactionItemReason::USER
+ );
+
+ // items are in reversed order than in test_install_downgrade_upgrade_remove()
+ // fixing this required ordering transaction items by forward/backward action
+ auto trans2 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::UPGRADE,
+ TransactionItemReason::USER
+ );
+ trans2->addItem(
+ nevraToRPMItem(conn, "tour-0:4.6-1.noarch"),
+ "repo2",
+ TransactionItemAction::UPGRADED,
+ TransactionItemReason::USER
+ );
+
+ auto trans3 = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans3->addItem(
+ nevraToRPMItem(conn, "tour-0:4.8-1.noarch"),
+ "repo1",
+ TransactionItemAction::REMOVE,
+ TransactionItemReason::USER
+ );
+
+ MergedTransaction merged(trans1);
+
+ // test merging trans1, trans2
+ merged.merge(trans2);
+ auto items2 = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(0, (int)items2.size());
+
+ // test merging trans1, trans2, trans3
+ merged.merge(trans3);
+ auto items3 = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(1, (int)items3.size());
+ auto item3 = items3.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item3->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item3->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REMOVE, item3->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
+}
+
+
+void
+MergedTransactionTest::test_multilib_identity()
+{
+ auto trans = std::make_shared< libdnf::swdb_private::Transaction >(conn);
+ trans->addItem(
+ nevraToRPMItem(conn, "gtk3-3.24.8-1.fc30.i686"),
+ "repo2",
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemReason::USER
+ );
+ trans->addItem(
+ nevraToRPMItem(conn, "gtk3-3.24.10-1.fc31.i686"),
+ "repo2",
+ TransactionItemAction::DOWNGRADED,
+ TransactionItemReason::USER
+ );
+ trans->addItem(
+ nevraToRPMItem(conn, "gtk3-3.24.8-1.fc30.x86_64"),
+ "repo2",
+ TransactionItemAction::DOWNGRADE,
+ TransactionItemReason::USER
+ );
+ trans->addItem(
+ nevraToRPMItem(conn, "gtk3-3.24.10-1.fc31.x86_64"),
+ "repo2",
+ TransactionItemAction::DOWNGRADED,
+ TransactionItemReason::USER
+ );
+
+ MergedTransaction merged(trans);
+
+ auto items = merged.getItems();
+ CPPUNIT_ASSERT_EQUAL(4, (int)items.size());
+
+ auto item0 = items.at(0);
+ CPPUNIT_ASSERT_EQUAL(std::string("gtk3-3.24.10-1.fc31.i686"), item0->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item0->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADED, item0->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item0->getReason());
+
+ auto item1 = items.at(1);
+ CPPUNIT_ASSERT_EQUAL(std::string("gtk3-3.24.8-1.fc30.i686"), item1->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item1->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADE, item1->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item1->getReason());
+
+ auto item2 = items.at(2);
+ CPPUNIT_ASSERT_EQUAL(std::string("gtk3-3.24.10-1.fc31.x86_64"), item2->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item2->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADED, item2->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
+
+ auto item3 = items.at(3);
+ CPPUNIT_ASSERT_EQUAL(std::string("gtk3-3.24.8-1.fc30.x86_64"), item3->getItem()->toStr());
+ CPPUNIT_ASSERT_EQUAL(std::string("repo2"), item3->getRepoid());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemAction::DOWNGRADE, item3->getAction());
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item3->getReason());
+}
+
+/*
+ def test_add_obsoleted_removed(self):
+ """Test add with an obsoleted NEVRA which was removed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'lotus-0:3-16.x86_64')
+
+ self.assertRaises(
+ ValueError,
+ ops.add, 'Install', 'tour-0:4.6-1.noarch', obsoleted_nevras=('lotus-0:3-16.x86_64',))
+
+ def test_add_reinstall_installed(self):
+ """Test add with a reinstall of NEVRA which was installed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Install', 'tour-0:4.6-1.noarch')
+ ops.add('Reinstall', 'tour-0:4.6-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Install', 'tour-0:4.6-1.noarch', None, set()),))
+
+ def test_add_replace_installed(self):
+ """Test add with a replacing NEVRA which was installed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Install', 'tour-0:4.8-1.noarch')
+
+ self.assertRaises(
+ ValueError,
+ ops.add, 'Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ def test_add_replace_opposite(self):
+ """Test add with a replacement which was done before, but swapped."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Downgrade', 'tour-0:4.6-1.noarch', 'tour-0:4.8-1.noarch')
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Reinstall', 'tour-0:4.8-1.noarch', 'tour-0:4.8-1.noarch', set()),))
+
+ def test_add_replace_opposite_manual(self):
+ """Test add with a manual replacement which was done before, but swapped."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'tour-0:4.8-1.noarch')
+ ops.add('Install', 'tour-0:4.6-1.noarch')
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Reinstall', 'tour-0:4.8-1.noarch', 'tour-0:4.8-1.noarch', set()),))
+
+ def test_add_replace_removed(self):
+ """Test add with a replacing NEVRA which was removed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'tour-0:4.8-1.noarch')
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Reinstall', 'tour-0:4.8-1.noarch', 'tour-0:4.8-1.noarch', set()),
+ ('Erase', 'tour-0:4.6-1.noarch', None, set())))
+
+ def test_add_replaced_opposite(self):
+ """Test add with a replaced NEVRA which replaced a NEVRA before in the opposite direction."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Downgrade', 'tour-0:4.6-1.noarch', 'tour-0:4.9-1.noarch')
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Erase', 'tour-0:4.9-1.noarch', None, set()),
+ ('Install', 'tour-0:4.8-1.noarch', None, set())))
+
+ def test_add_replaced_removed(self):
+ """Test add with a replaced NEVRA which was removed before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Erase', 'tour-0:4.6-1.noarch')
+
+ self.assertRaises(
+ ValueError,
+ ops.add, 'Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ def test_add_replaced_reinstall(self):
+ """Test add with a replaced NEVRA which was reinstalled before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Reinstall', 'tour-0:4.6-1.noarch', 'tour-0:4.6-1.noarch')
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch', set()),))
+
+ def test_add_replaced_replacement(self):
+ """Test add with a replaced NEVRA which replaced a NEVRA before."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ self.assertCountEqual(
+ ops,
+ (('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.6-1.noarch', set()),))
+
+ def test_addition(self):
+ """Test addition of two instances."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+ expected_ops = dnf.history.NEVRAOperations()
+ expected_ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.6-1.noarch')
+
+ result_ops = left_ops + right_ops
+
+ self.assertEqual(result_ops, expected_ops)
+
+ def test_addition_inplace(self):
+ """Test in-place addition of two instances."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+ expected_ops = dnf.history.NEVRAOperations()
+ expected_ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.6-1.noarch')
+
+ left_ops += right_ops
+
+ self.assertEqual(left_ops, expected_ops)
+
+ def test_equality(self):
+ """Test equality of two equal instances."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_equal = left_ops == right_ops
+
+ self.assertTrue(is_equal)
+
+ def test_equality_differentcontent(self):
+ """Test equality of two instances with different contents."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Downgrade', 'tour-0:4.6-1.noarch', 'tour-0:4.8-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_equal = left_ops == right_ops
+
+ self.assertFalse(is_equal)
+
+ def test_equality_differentlength(self):
+ """Test equality of two instances with different lengths."""
+ left_ops = dnf.history.NEVRAOperations()
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_equal = left_ops == right_ops
+
+ self.assertFalse(is_equal)
+
+ def test_equality_differenttype(self):
+ """Test equality of an instance and an object of a different type."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_equal = ops == 'tour-0:4.8-1.noarch'
+
+ self.assertFalse(is_equal)
+
+ def test_equality_identity(self):
+ """Test equality of the same instance."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_equal = ops == ops
+
+ self.assertTrue(is_equal)
+
+ def test_inequality(self):
+ """Test inequality of two different instances."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Downgrade', 'tour-0:4.6-1.noarch', 'tour-0:4.8-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_inequal = left_ops != right_ops
+
+ self.assertTrue(is_inequal)
+
+ def test_inequality_equal(self):
+ """Test inequality of two equal instances."""
+ left_ops = dnf.history.NEVRAOperations()
+ left_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+ right_ops = dnf.history.NEVRAOperations()
+ right_ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ is_inequal = left_ops != right_ops
+
+ self.assertFalse(is_inequal)
+
+ def test_iterator(self):
+ """Test iterator of an instance."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ iterator = iter(ops)
+
+ self.assertEqual(
+ next(iterator),
+ ('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch', set()))
+ self.assertRaises(StopIteration, next, iterator)
+
+ def test_length(self):
+ """Test length of an instance."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.8-1.noarch', 'tour-0:4.6-1.noarch')
+
+ length = len(ops)
+
+ self.assertEqual(length, 1)
+
+ def test_membership(self):
+ """Test membership of a contained operation."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ is_in = ('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch', ()) in ops
+
+ self.assertTrue(is_in)
+
+ def test_membership_differentnevra(self):
+ """Test membership of an operation with different (replacing) NEVRA."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ is_in = ('Update', 'pepper-0:20-0.x86_64', 'tour-0:4.8-1.noarch', ()) in ops
+
+ self.assertFalse(is_in)
+
+ def test_membership_differentobsoleted(self):
+ """Test membership of an operation with different obsoleted NEVRAs."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+ op = (
+ 'Update',
+ 'tour-0:4.9-1.noarch',
+ 'tour-0:4.8-1.noarch',
+ ('pepper-0:20-0.x86_64',)
+ )
+ self.assertFalse(op in ops)
+
+ def test_membership_differentreplaced(self):
+ """Test membership of an operation with different replaced NEVRA."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ is_in = ('Update', 'tour-0:4.9-1.noarch', 'pepper-0:20-0.x86_64', ()) in ops
+
+ self.assertFalse(is_in)
+
+ def test_membership_differentstate(self):
+ """Test membership of an operation with different state."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ is_in = ('Downgrade', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch', ()) in ops
+
+ self.assertFalse(is_in)
+
+ def test_membership_differenttype(self):
+ """Test membership of an object of a different type."""
+ ops = dnf.history.NEVRAOperations()
+ ops.add('Update', 'tour-0:4.9-1.noarch', 'tour-0:4.8-1.noarch')
+
+ is_in = 'tour-0:4.9-1.noarch' in ops
+
+ self.assertFalse(is_in)
+*/
--- /dev/null
+#ifndef LIBDNF_SWDB_MERGEDTRANSACTION_TEST_HPP
+#define LIBDNF_SWDB_MERGEDTRANSACTION_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class MergedTransactionTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(MergedTransactionTest);
+// CPPUNIT_TEST(testMerge);
+// CPPUNIT_TEST(testMergeEraseInstallReinstall);
+// CPPUNIT_TEST(testMergeEraseInstallDowngrade);
+// CPPUNIT_TEST(testMergeEraseInstallUpgrade);
+// CPPUNIT_TEST(testMergeReinstallAny);
+// CPPUNIT_TEST(testMergeInstallErase);
+// CPPUNIT_TEST(testMergeInstallAlter);
+// CPPUNIT_TEST(testMergeAlterReinstall);
+// CPPUNIT_TEST(testMergeAlterErase);
+// CPPUNIT_TEST(testMergeAlterAlter);
+ CPPUNIT_TEST(test_add_remove_installed);
+ CPPUNIT_TEST(test_add_remove_removed);
+ CPPUNIT_TEST(test_add_install_installed);
+ CPPUNIT_TEST(test_add_install_removed);
+ CPPUNIT_TEST(test_add_obsoleted_installed);
+ CPPUNIT_TEST(test_add_obsoleted_obsoleted);
+
+ CPPUNIT_TEST(test_downgrade);
+ CPPUNIT_TEST(test_install_downgrade_upgrade_remove);
+ CPPUNIT_TEST(test_downgrade_upgrade_remove);
+
+ CPPUNIT_TEST(test_multilib_identity);
+
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testMerge();
+ void testMergeEraseInstallReinstall();
+ void testMergeEraseInstallDowngrade();
+ void testMergeEraseInstallUpgrade();
+ void testMergeReinstallAny();
+ void testMergeInstallErase();
+ void testMergeInstallAlter();
+ void testMergeAlterReinstall();
+ void testMergeAlterErase();
+ void testMergeAlterAlter();
+ // BEGIN: tests ported from DNF unit tests
+ void test_add_remove_installed();
+ void test_add_remove_removed();
+ void test_add_install_installed();
+ void test_add_install_removed();
+ void test_add_obsoleted_installed();
+ void test_add_obsoleted_obsoleted();
+ // END: tests ported from DNF unit tests
+
+ void test_downgrade();
+ void test_install_downgrade_upgrade_remove();
+ void test_downgrade_upgrade_remove();
+
+ void test_multilib_identity();
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_MERGEDTRANSACTION_TEST_HPP
--- /dev/null
+#include <string>
+
+#include "libdnf/transaction/Swdb.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "MigrationTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(MigrationTest);
+
+static const char * const test_sql_create_tables =
+#include "libdnf/transaction/sql/create_tables.sql"
+ ;
+
+void
+MigrationTest::setUp()
+{
+ history = std::make_shared< SQLite3 >(":memory:");
+ history.get()->exec(test_sql_create_tables);
+}
+
+void
+MigrationTest::testVersionMissing()
+{
+ history.get()->exec("delete from config where key='version';");
+ try{
+ Swdb swdb(history);
+ }
+ catch (Transformer::Exception & ex) {
+ CPPUNIT_ASSERT_EQUAL(
+ std::string(ex.what()),
+ std::string("Database Corrupted: no row 'version' in table 'config'"));
+ }
+}
+
+void
+MigrationTest::testVersionBeforeMigration()
+{
+ SQLite3::Query query(*history, "select value from config where key = 'version';");
+ query.step();
+ // hardcoded 1.1 is fine since it is the initial version
+ CPPUNIT_ASSERT_EQUAL(query.get<std::string>("value"), std::string("1.1"));
+}
+
+void
+MigrationTest::testVersionAfterMigration()
+{
+ Swdb swdb(history);
+ SQLite3::Query query(*history, "select value from config where key = 'version';");
+ query.step();
+ CPPUNIT_ASSERT_EQUAL(query.get<std::string>("value"), std::string(Transformer::getVersion()));
+}
+
+void
+MigrationTest::testEmptyCommentAfterMigration()
+{
+ history.get()->exec("INSERT INTO trans VALUES(1,1,1,'','','1',-1,'',1);"); // make record of old transaction
+ Swdb swdb(history); // migrate
+ Transaction trans(history, 1);
+ CPPUNIT_ASSERT_EQUAL(trans.getComment(), std::string());
+}
+
+void
+MigrationTest::testNonEmptyCommentAfterMigration()
+{
+ Swdb swdb(history); // migrate
+ swdb.initTransaction();
+ swdb.beginTransaction(1, "", "", 0, "Test comment");
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+ Transaction trans(history, 1);
+ CPPUNIT_ASSERT_EQUAL(trans.getComment(), std::string("Test comment"));
+}
+
+void
+MigrationTest::tearDown()
+{
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_MIGRATION_TEST_HPP
+#define LIBDNF_SWDB_MIGRATION_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class MigrationTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(MigrationTest);
+ CPPUNIT_TEST(testVersionMissing);
+ CPPUNIT_TEST(testVersionBeforeMigration);
+ CPPUNIT_TEST(testVersionAfterMigration);
+ CPPUNIT_TEST(testEmptyCommentAfterMigration);
+ CPPUNIT_TEST(testNonEmptyCommentAfterMigration);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testVersionMissing();
+ void testVersionBeforeMigration();
+ void testVersionAfterMigration();
+ void testEmptyCommentAfterMigration();
+ void testNonEmptyCommentAfterMigration();
+
+private:
+ std::shared_ptr< SQLite3 > history;
+};
+
+#endif // LIBDNF_SWDB_MIGRATION_TEST_HPP
--- /dev/null
+#include <chrono>
+#include <cstdio>
+#include <iostream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "RpmItemTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RpmItemTest);
+
+void
+RpmItemTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+RpmItemTest::tearDown()
+{
+}
+
+void
+RpmItemTest::testCreate()
+{
+ // bash-4.4.12-5.fc26.x86_64
+ RPMItem rpm(conn);
+ rpm.setName("bash");
+ rpm.setEpoch(0);
+ rpm.setVersion("4.4.12");
+ rpm.setRelease("5.fc26");
+ rpm.setArch("x86_64");
+ rpm.save();
+
+ RPMItem rpm2(conn, rpm.getId());
+ CPPUNIT_ASSERT(rpm2.getId() == rpm.getId());
+ CPPUNIT_ASSERT(rpm2.getName() == rpm.getName());
+ CPPUNIT_ASSERT(rpm2.getEpoch() == rpm.getEpoch());
+ CPPUNIT_ASSERT(rpm2.getVersion() == rpm.getVersion());
+ CPPUNIT_ASSERT(rpm2.getRelease() == rpm.getRelease());
+}
+
+void
+RpmItemTest::testCreateDuplicates()
+{
+ // bash-4.4.12-5.fc26.x86_64
+ auto rpm = std::make_shared< RPMItem >(conn);
+ rpm->setName("bash");
+ rpm->setEpoch(0);
+ rpm->setVersion("4.4.12");
+ rpm->setRelease("5.fc26");
+ rpm->setArch("x86_64");
+
+ libdnf::swdb_private::Transaction trans(conn);
+
+ // add a RPM twice, but with different reasons
+ auto ti1 = trans.addItem(rpm, "base", TransactionItemAction::INSTALL, TransactionItemReason::GROUP);
+ auto ti2 = trans.addItem(rpm, "base", TransactionItemAction::INSTALL, TransactionItemReason::DEPENDENCY);
+ // test that the duplicate wasn't inserted
+ CPPUNIT_ASSERT(trans.getItems().size() == 1);
+ // test that the best reason (from ti1) was used
+ CPPUNIT_ASSERT(ti1->getReason() == TransactionItemReason::GROUP);
+ CPPUNIT_ASSERT(ti2->getReason() == TransactionItemReason::GROUP);
+
+ auto ti3 = trans.addItem(rpm, "base", TransactionItemAction::INSTALL, TransactionItemReason::USER);
+ // test that the duplicate wasn't inserted
+ CPPUNIT_ASSERT(trans.getItems().size() == 1);
+ // test that the best reason (from ti3) was used
+ CPPUNIT_ASSERT(ti1->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(ti2->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(ti3->getReason() == TransactionItemReason::USER);
+}
+
+void
+RpmItemTest::testGetTransactionItems()
+{
+ // performance looks good: 100k records take roughly 3.3s to write, 0.2s to read
+ // change following constant to modify number of tested RPMItems
+ constexpr int num = 10;
+
+ libdnf::swdb_private::Transaction trans(conn);
+
+ auto create_start = std::chrono::high_resolution_clock::now();
+ for (int i = 0; i < num; i++) {
+ auto rpm = std::make_shared< RPMItem >(conn);
+ rpm->setName("name_" + std::to_string(i));
+ rpm->setEpoch(0);
+ rpm->setVersion("1");
+ rpm->setRelease("2");
+ rpm->setArch("x86_64");
+ auto ti = trans.addItem(rpm, "base", TransactionItemAction::INSTALL, TransactionItemReason::USER);
+ ti->setState(TransactionItemState::DONE);
+ }
+ trans.begin();
+ trans.finish(TransactionState::DONE);
+ auto create_finish = std::chrono::high_resolution_clock::now();
+ std::chrono::duration< double > create_duration = create_finish - create_start;
+
+ auto read_start = std::chrono::high_resolution_clock::now();
+ auto items = RPMItem::getTransactionItems(conn, trans.getId());
+ for (auto i : items) {
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(i->getItem());
+ // std::cout << rpm->getNEVRA() << std::endl;
+ }
+ auto read_finish = std::chrono::high_resolution_clock::now();
+ std::chrono::duration< double > read_duration = read_finish - read_start;
+
+ auto createMs = std::chrono::duration_cast< std::chrono::milliseconds >(create_duration);
+ (void)createMs;
+ auto readMs = std::chrono::duration_cast< std::chrono::milliseconds >(read_duration);
+ (void)readMs;
+
+ //CPPUNIT_ASSERT(createMs.count() == 0);
+ //CPPUNIT_ASSERT(readMs.count() == 0);
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_RPMITEM_TEST_HPP
+#define LIBDNF_SWDB_RPMITEM_TEST_HPP
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class RpmItemTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(RpmItemTest);
+ CPPUNIT_TEST(testCreate);
+ CPPUNIT_TEST(testCreateDuplicates);
+ CPPUNIT_TEST(testGetTransactionItems);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testCreate();
+ void testCreateDuplicates();
+ void testGetTransactionItems();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_RPMITEM_TEST_HPP
--- /dev/null
+#include <cstdio>
+#include <iostream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/CompsEnvironmentItem.hpp"
+#include "libdnf/transaction/CompsGroupItem.hpp"
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/Swdb.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/TransactionItem.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "TransactionItemReasonTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TransactionItemReasonTest);
+
+void
+TransactionItemReasonTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+TransactionItemReasonTest::tearDown()
+{
+}
+
+// no transactions -> UNKNOWN reason
+void
+TransactionItemReasonTest::testNoTransaction()
+{
+ Swdb swdb(conn);
+
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::UNKNOWN);
+}
+
+// one transaction with no transaction items -> UNKNOWN reason
+void
+TransactionItemReasonTest::testEmptyTransaction()
+{
+ Swdb swdb(conn);
+
+ swdb.initTransaction();
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::UNKNOWN);
+}
+
+// one transaction with one transaction item -> $reason
+void
+TransactionItemReasonTest::test_OneTransaction_OneTransactionItem()
+{
+ Swdb swdb(conn);
+
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::GROUP);
+
+ // package does not exist -> UNKNOWN
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "i686", -1)),
+ TransactionItemReason::UNKNOWN);
+
+ // package exists, arch not specified -> return best $reason
+ CPPUNIT_ASSERT_EQUAL(
+ static_cast< TransactionItemReason >(swdb.resolveRPMTransactionItemReason("bash", "", -1)),
+ TransactionItemReason::GROUP);
+}
+
+// one FAILED transaction with one transaction item -> $reason
+void
+TransactionItemReasonTest::test_OneFailedTransaction_OneTransactionItem()
+{
+ Swdb swdb(conn);
+
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::ERROR);
+ swdb.closeTransaction();
+
+ // failed transaction -> UNKNOWN
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::UNKNOWN);
+
+ // failed transaction -> UNKNOWN
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "i686", -1)),
+ TransactionItemReason::UNKNOWN);
+
+ // failed transaction -> UNKNOWN
+ CPPUNIT_ASSERT_EQUAL(
+ static_cast< TransactionItemReason >(swdb.resolveRPMTransactionItemReason("bash", "", -1)),
+ TransactionItemReason::UNKNOWN);
+}
+
+// one transaction with two transaction items -> $reason
+void
+TransactionItemReasonTest::test_OneTransaction_TwoTransactionItems()
+{
+ Swdb swdb(conn);
+
+ swdb.initTransaction();
+
+ {
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+ }
+
+ {
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("i686");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::USER;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+ }
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::GROUP);
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "i686", -1)),
+ TransactionItemReason::USER);
+
+ // 2 packages exists, arch not specified -> return best $reason
+ CPPUNIT_ASSERT_EQUAL(
+ static_cast< TransactionItemReason >(swdb.resolveRPMTransactionItemReason("bash", "", -1)),
+ TransactionItemReason::USER);
+}
+
+// two transactions with two transaction items -> $reason
+void
+TransactionItemReasonTest::test_TwoTransactions_TwoTransactionItems()
+{
+ Swdb swdb(conn);
+
+ {
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+ }
+
+ {
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("i686");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::USER;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+ }
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)),
+ TransactionItemReason::GROUP);
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "i686", -1)),
+ TransactionItemReason::USER);
+
+ // 2 packages exists, arch not specified -> return best $reason
+ CPPUNIT_ASSERT_EQUAL(
+ static_cast< TransactionItemReason >(swdb.resolveRPMTransactionItemReason("bash", "", -1)),
+ TransactionItemReason::USER);
+}
+
+//
+void
+TransactionItemReasonTest::testRemovedPackage()
+{
+ Swdb swdb(conn);
+
+ {
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+ }
+
+ {
+ swdb.initTransaction();
+
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("i686");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::USER;
+ auto ti = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti->setState(TransactionItemState::DONE);
+
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+
+ swdb.initTransaction();
+ action = TransactionItemAction::REMOVE;
+ auto ti_remove = swdb.addItem(rpm_bash, repoid, action, reason);
+ ti_remove->setState(TransactionItemState::DONE);
+ swdb.beginTransaction(1, "", "", 0);
+ swdb.endTransaction(2, "", TransactionState::DONE);
+ swdb.closeTransaction();
+ }
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::GROUP,
+ static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "x86_64", -1)));
+
+ // package exists -> $reason
+ CPPUNIT_ASSERT_EQUAL(TransactionItemReason::UNKNOWN,
+ static_cast< TransactionItemReason >(
+ swdb.resolveRPMTransactionItemReason("bash", "i686", -1)));
+
+ // 2 packages exists, arch not specified -> return best $reason
+ CPPUNIT_ASSERT_EQUAL(
+ TransactionItemReason::GROUP,
+ static_cast< TransactionItemReason >(swdb.resolveRPMTransactionItemReason("bash", "", -1)));
+}
+
+void
+TransactionItemReasonTest::testCompareReasons()
+{
+ CPPUNIT_ASSERT(TransactionItemReason::USER == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(TransactionItemReason::USER <= TransactionItemReason::USER);
+ CPPUNIT_ASSERT(TransactionItemReason::USER >= TransactionItemReason::USER);
+
+ CPPUNIT_ASSERT(TransactionItemReason::USER != TransactionItemReason::GROUP);
+ CPPUNIT_ASSERT(TransactionItemReason::USER > TransactionItemReason::GROUP);
+ CPPUNIT_ASSERT(TransactionItemReason::USER >= TransactionItemReason::GROUP);
+
+ CPPUNIT_ASSERT(TransactionItemReason::GROUP != TransactionItemReason::USER);
+ CPPUNIT_ASSERT(TransactionItemReason::GROUP < TransactionItemReason::USER);
+ CPPUNIT_ASSERT(TransactionItemReason::GROUP <= TransactionItemReason::USER);
+
+ CPPUNIT_ASSERT(TransactionItemReason::UNKNOWN < TransactionItemReason::USER);
+ CPPUNIT_ASSERT(TransactionItemReason::GROUP > TransactionItemReason::UNKNOWN);
+ CPPUNIT_ASSERT(TransactionItemReason::DEPENDENCY < TransactionItemReason::UNKNOWN);
+ CPPUNIT_ASSERT(TransactionItemReason::WEAK_DEPENDENCY < TransactionItemReason::UNKNOWN);
+ CPPUNIT_ASSERT(TransactionItemReason::CLEAN < TransactionItemReason::UNKNOWN);
+ CPPUNIT_ASSERT(TransactionItemReason::WEAK_DEPENDENCY < TransactionItemReason::DEPENDENCY);
+ CPPUNIT_ASSERT(TransactionItemReason::CLEAN < TransactionItemReason::WEAK_DEPENDENCY);
+}
+
+void
+TransactionItemReasonTest::testTransactionItemReasonCompare()
+{
+ CPPUNIT_ASSERT_EQUAL(-1, TransactionItemReasonCompare(TransactionItemReason::GROUP, TransactionItemReason::USER));
+ CPPUNIT_ASSERT_EQUAL(0, TransactionItemReasonCompare(TransactionItemReason::USER, TransactionItemReason::USER));
+ CPPUNIT_ASSERT_EQUAL(1, TransactionItemReasonCompare(TransactionItemReason::USER, TransactionItemReason::GROUP));
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_TRANSACTION_ITEM_REASON_TEST_HPP
+#define LIBDNF_SWDB_TRANSACTION_ITEM_REASON_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class TransactionItemReasonTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(TransactionItemReasonTest);
+ CPPUNIT_TEST(testNoTransaction);
+ CPPUNIT_TEST(testEmptyTransaction);
+ CPPUNIT_TEST(test_OneTransaction_OneTransactionItem);
+ CPPUNIT_TEST(test_OneFailedTransaction_OneTransactionItem);
+ CPPUNIT_TEST(test_OneTransaction_TwoTransactionItems);
+ CPPUNIT_TEST(test_TwoTransactions_TwoTransactionItems);
+ CPPUNIT_TEST(testRemovedPackage);
+ CPPUNIT_TEST(testCompareReasons);
+ CPPUNIT_TEST(testTransactionItemReasonCompare);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testNoTransaction();
+ void testEmptyTransaction();
+ void test_OneTransaction_OneTransactionItem();
+ void test_OneFailedTransaction_OneTransactionItem();
+ void test_OneTransaction_TwoTransactionItems();
+ void test_TwoTransactions_TwoTransactionItems();
+ void testRemovedPackage();
+ void testCompareReasons();
+ void testTransactionItemReasonCompare();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_TRANSACTION_ITEM_REASON_TEST_HPP
--- /dev/null
+#include "libdnf/hy-subject.h"
+#include "libdnf/nevra.hpp"
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/private/Transaction.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+
+#include "../backports.hpp"
+
+#include "TransactionTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TransactionTest);
+
+static RPMItemPtr
+nevraToRPMItem(SQLite3Ptr conn, std::string nevra)
+{
+ libdnf::Nevra nevraObject;
+ if (!nevraObject.parse(nevra.c_str(), HY_FORM_NEVRA)) {
+ return nullptr;
+ }
+ if (nevraObject.getEpoch() < 0) {
+ nevraObject.setEpoch(0);
+ }
+
+ auto rpm = std::make_shared< RPMItem >(conn);
+ rpm->setName(nevraObject.getName());
+ rpm->setEpoch(nevraObject.getEpoch());
+ rpm->setVersion(nevraObject.getVersion());
+ rpm->setRelease(nevraObject.getRelease());
+ rpm->setArch(nevraObject.getArch());
+ return rpm;
+}
+
+void
+TransactionTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+TransactionTest::tearDown()
+{
+}
+
+void
+TransactionTest::testInsert()
+{
+ libdnf::swdb_private::Transaction trans(conn);
+ trans.setDtBegin(1);
+ trans.setDtEnd(2);
+ trans.setRpmdbVersionBegin("begin - TransactionTest::testInsert");
+ trans.setRpmdbVersionEnd("end - TransactionTest::testInsert");
+ trans.setReleasever("26");
+ trans.setUserId(1000);
+ trans.setCmdline("dnf install foo");
+ trans.setState(TransactionState::DONE);
+
+ trans.addSoftwarePerformedWith(nevraToRPMItem(conn, "rpm-4.14.2-1.fc29.x86_64"));
+ trans.addSoftwarePerformedWith(nevraToRPMItem(conn, "dnf-3.5.1-1.fc29.noarch"));
+ // test adding a duplicate; only a single occurrence of the rpm is expected
+ trans.addSoftwarePerformedWith(nevraToRPMItem(conn, "rpm-4.14.2-1.fc29.x86_64"));
+
+ trans.begin();
+
+ // getSoftwarePerformedWith returns results directly from the db
+ // that's why it has to be called after begin(), where the records are saved
+ CPPUNIT_ASSERT(trans.getSoftwarePerformedWith().size() == 2);
+
+ // 2nd begin must throw an exception
+ CPPUNIT_ASSERT_THROW(trans.begin(), std::runtime_error);
+
+ // load the saved transaction from database and compare values
+ libdnf::Transaction trans2(conn, trans.getId());
+ CPPUNIT_ASSERT(trans2.getId() == trans.getId());
+ CPPUNIT_ASSERT(trans2.getDtBegin() == trans.getDtBegin());
+ CPPUNIT_ASSERT(trans2.getDtEnd() == trans.getDtEnd());
+ CPPUNIT_ASSERT(trans2.getRpmdbVersionBegin() == trans.getRpmdbVersionBegin());
+ CPPUNIT_ASSERT(trans2.getRpmdbVersionEnd() == trans.getRpmdbVersionEnd());
+ CPPUNIT_ASSERT(trans2.getReleasever() == trans.getReleasever());
+ CPPUNIT_ASSERT(trans2.getUserId() == trans.getUserId());
+ CPPUNIT_ASSERT(trans2.getCmdline() == trans.getCmdline());
+ CPPUNIT_ASSERT(trans2.getState() == trans.getState());
+ CPPUNIT_ASSERT(trans2.getSoftwarePerformedWith().size() == 2);
+}
+
+void
+TransactionTest::testInsertWithSpecifiedId()
+{
+ // it is not allowed to save a transaction with arbitrary ID
+ libdnf::swdb_private::Transaction trans(conn);
+ trans.setId(INT64_MAX);
+ CPPUNIT_ASSERT_THROW(trans.begin(), std::runtime_error);
+}
+
+void
+TransactionTest::testUpdate()
+{
+ libdnf::swdb_private::Transaction trans(conn);
+ trans.setDtBegin(1);
+ trans.setDtEnd(2);
+ trans.setRpmdbVersionBegin("begin - TransactionTest::testInsert");
+ trans.setRpmdbVersionEnd("end - TransactionTest::testInsert");
+ trans.setReleasever("26");
+ trans.setUserId(1000);
+ trans.setCmdline("dnf install foo");
+ trans.setState(TransactionState::ERROR);
+ trans.begin();
+ trans.finish(TransactionState::DONE);
+
+ libdnf::Transaction trans2(conn, trans.getId());
+ CPPUNIT_ASSERT(trans2.getId() == trans.getId());
+ CPPUNIT_ASSERT(trans2.getDtBegin() == trans.getDtBegin());
+ CPPUNIT_ASSERT(trans2.getDtEnd() == trans.getDtEnd());
+ CPPUNIT_ASSERT(trans2.getRpmdbVersionBegin() == trans.getRpmdbVersionBegin());
+ CPPUNIT_ASSERT(trans2.getRpmdbVersionEnd() == trans.getRpmdbVersionEnd());
+ CPPUNIT_ASSERT(trans2.getReleasever() == trans.getReleasever());
+ CPPUNIT_ASSERT(trans2.getUserId() == trans.getUserId());
+ CPPUNIT_ASSERT(trans2.getCmdline() == trans.getCmdline());
+ CPPUNIT_ASSERT_EQUAL(TransactionState::DONE, trans2.getState());
+}
+
+void
+TransactionTest::testComparison()
+{
+ // test operator ==, > and <
+ libdnf::swdb_private::Transaction first(conn);
+ libdnf::swdb_private::Transaction second(conn);
+
+ // id comparison test
+ first.setId(1);
+ second.setId(2);
+ CPPUNIT_ASSERT(first > second);
+ CPPUNIT_ASSERT(second < first);
+
+ // begin timestamp comparison test
+ second.setId(1);
+ first.setDtBegin(1);
+ second.setDtBegin(2);
+ CPPUNIT_ASSERT(first > second);
+ CPPUNIT_ASSERT(second < first);
+
+ // rpmdb comparison test
+ second.setDtBegin(1);
+ first.setRpmdbVersionBegin("0");
+ second.setRpmdbVersionBegin("1");
+ CPPUNIT_ASSERT(first > second);
+ CPPUNIT_ASSERT(second < first);
+
+ // equality
+ second.setRpmdbVersionBegin("0");
+ CPPUNIT_ASSERT(first == second);
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_TRANSACTION_TEST_HPP
+#define LIBDNF_SWDB_TRANSACTION_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class TransactionTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(TransactionTest);
+ CPPUNIT_TEST(testInsert);
+ CPPUNIT_TEST(testInsertWithSpecifiedId);
+ CPPUNIT_TEST(testUpdate);
+ CPPUNIT_TEST(testComparison);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testInsert();
+ void testInsertWithSpecifiedId();
+ void testUpdate();
+ void testComparison();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_TRANSACTION_TEST_HPP
--- /dev/null
+#include <json.h>
+#include <set>
+#include <sstream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/Swdb.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/private/Transaction.hpp"
+#include "libdnf/transaction/TransactionItem.hpp"
+#include "libdnf/transaction/Types.hpp"
+
+#include "TransformerTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TransformerTest);
+
+TransformerMock::TransformerMock()
+ : Transformer("", "")
+{
+}
+
+static const char *create_history_sql =
+#include "sql/create_test_history_db.sql"
+ ;
+
+static const char *groups_json =
+#include "assets/groups.json"
+ ;
+
+void
+TransformerTest::setUp()
+{
+ swdb = std::make_shared< SQLite3 >(":memory:");
+ history = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(swdb);
+ history.get()->exec(create_history_sql);
+}
+
+void
+TransformerTest::tearDown()
+{
+}
+
+void
+TransformerTest::testGroupTransformation()
+{
+ // load test groups.json
+ struct json_object *groupsJson = json_tokener_parse (groups_json);
+
+ // perform the transformation
+ transformer.processGroupPersistor(swdb, groupsJson);
+
+ swdb->backup("db.sql");
+
+ // check basic stuff in generated transaction
+ libdnf::Transaction trans(swdb, 1);
+ CPPUNIT_ASSERT_EQUAL((int64_t)1, trans.getId());
+ CPPUNIT_ASSERT_EQUAL(TransactionState::DONE, trans.getState());
+
+ // load transaction items
+ auto items = trans.getItems();
+ CPPUNIT_ASSERT_EQUAL(2, static_cast< int >(items.size()));
+
+ // verify items
+ for (auto transItem : items) {
+ auto item = transItem->getItem();
+ auto type = item->getItemType();
+ if (type == ItemType::GROUP) {
+ auto group = std::dynamic_pointer_cast< CompsGroupItem >(item);
+
+ CPPUNIT_ASSERT(group->getGroupId() == "core");
+ CPPUNIT_ASSERT("Core" == group->getName());
+ CPPUNIT_ASSERT("Úplný základ" == group->getTranslatedName());
+
+ auto packages = group->getPackages();
+
+ CPPUNIT_ASSERT(1 == packages.size());
+
+ auto groupPkg = packages[0];
+ CPPUNIT_ASSERT(groupPkg->getName() == "dnf-yum");
+ CPPUNIT_ASSERT(groupPkg->getInstalled() == true);
+ CPPUNIT_ASSERT(groupPkg->getPackageType() == CompsPackageType::MANDATORY);
+
+ } else if (type == ItemType::ENVIRONMENT) {
+ auto env = std::dynamic_pointer_cast< CompsEnvironmentItem >(item);
+ CPPUNIT_ASSERT("minimal-environment" == env->getEnvironmentId());
+ CPPUNIT_ASSERT("Minimal Install" == env->getName());
+ CPPUNIT_ASSERT("Minimálna inštalácia" == env->getTranslatedName());
+
+ auto groups = env->getGroups();
+ CPPUNIT_ASSERT(1 == groups.size());
+
+ auto envGroup = groups[0];
+ CPPUNIT_ASSERT(envGroup->getGroupId() == "core");
+ CPPUNIT_ASSERT(envGroup->getInstalled() == true);
+ CPPUNIT_ASSERT(envGroup->getGroupType() == CompsPackageType::MANDATORY);
+
+ } else {
+ CPPUNIT_FAIL("Invalid item type: " + std::to_string(static_cast< int >(type)));
+ }
+ }
+
+ json_object_put(groupsJson);
+}
+
+void
+TransformerTest::testTransformTrans()
+{
+ // perform database transformation
+ transformer.transformTrans(swdb, history);
+
+ // check first transaction attributes
+ libdnf::Transaction first(swdb, 1);
+ CPPUNIT_ASSERT(first.getId() == 1);
+ CPPUNIT_ASSERT(first.getDtBegin() == 1513267401);
+ CPPUNIT_ASSERT(first.getDtEnd() == 1513267509);
+ CPPUNIT_ASSERT(first.getRpmdbVersionBegin() == "2213:9795b6a4db5e5368628b5240ec63a629833c5594");
+ CPPUNIT_ASSERT(first.getRpmdbVersionEnd() == "2213:9eab991133c166f8bcf3ecea9fb422b853f7aebc");
+ CPPUNIT_ASSERT(first.getReleasever() == "26");
+ CPPUNIT_ASSERT(first.getUserId() == 1000);
+ CPPUNIT_ASSERT(first.getCmdline() == "upgrade -y");
+ CPPUNIT_ASSERT(first.getState() == TransactionState::DONE);
+
+ // check first transaction output
+ auto firstOut = first.getConsoleOutput();
+ CPPUNIT_ASSERT(firstOut.size() == 2);
+ CPPUNIT_ASSERT(firstOut[0].first == 1);
+ CPPUNIT_ASSERT(firstOut[0].second == "line1");
+ CPPUNIT_ASSERT(firstOut[1].first == 1);
+ CPPUNIT_ASSERT(firstOut[1].second == "line2");
+
+ // check software performed with
+ auto firstSoftWith = first.getSoftwarePerformedWith();
+ CPPUNIT_ASSERT(firstSoftWith.size() == 1);
+ for (auto soft : firstSoftWith) {
+ CPPUNIT_ASSERT(soft->getId() == 2);
+ }
+
+ // check first transaction items
+ auto items = first.getItems();
+ CPPUNIT_ASSERT(items.size() == 2);
+ for (auto item : items) {
+ auto rpm = std::dynamic_pointer_cast< RPMItem >(item->getItem());
+ if (rpm->getName() == "chrony" && rpm->getVersion() == "3.1") {
+ CPPUNIT_ASSERT(rpm->getEpoch() == 1);
+ CPPUNIT_ASSERT(rpm->getRelease() == "4.fc26");
+ CPPUNIT_ASSERT(item->getAction() == TransactionItemAction::UPGRADED);
+ CPPUNIT_ASSERT(item->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(item->getState() == TransactionItemState::DONE);
+
+ // TODO repo, replaced
+ } else { // chrony 3.2
+ CPPUNIT_ASSERT(rpm->getEpoch() == 1);
+ CPPUNIT_ASSERT(rpm->getVersion() == "3.2");
+ CPPUNIT_ASSERT(rpm->getRelease() == "4.fc26");
+
+ CPPUNIT_ASSERT(item->getAction() == TransactionItemAction::UPGRADE);
+ CPPUNIT_ASSERT(item->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(item->getState() == TransactionItemState::DONE);
+ // TODO repo, replaced
+ }
+ }
+
+ // check second transaction attributes
+ libdnf::Transaction second(swdb, 2);
+ CPPUNIT_ASSERT(second.getId() == 2);
+ CPPUNIT_ASSERT(second.getDtBegin() == 1513267535);
+ CPPUNIT_ASSERT(second.getDtEnd() == 1513267539);
+ CPPUNIT_ASSERT(second.getRpmdbVersionBegin() ==
+ "2213:9eab991133c166f8bcf3ecea9fb422b853f7aebc");
+ CPPUNIT_ASSERT(second.getRpmdbVersionEnd() == "2214:e02004142740afb5b6d148d50bc84be4ab41ad13");
+ CPPUNIT_ASSERT(second.getUserId() == 1000);
+ CPPUNIT_ASSERT(second.getCmdline() == "-y install Foo");
+ CPPUNIT_ASSERT(second.getState() == TransactionState::DONE);
+
+ // check second transaction console output
+ auto secondOut = second.getConsoleOutput();
+ CPPUNIT_ASSERT(secondOut.size() == 2);
+ CPPUNIT_ASSERT(secondOut[0].first == 2);
+ CPPUNIT_ASSERT(secondOut[0].second == "msg1");
+ CPPUNIT_ASSERT(secondOut[1].first == 2);
+ CPPUNIT_ASSERT(secondOut[1].second == "msg2");
+
+ // check second transaction performed with software
+ std::set< int64_t > possibleValues = {2, 3};
+ auto secondSoftWith = second.getSoftwarePerformedWith();
+ CPPUNIT_ASSERT(secondSoftWith.size() == 2);
+ for (auto soft : secondSoftWith) {
+ auto it = possibleValues.find(soft->getId());
+ CPPUNIT_ASSERT(it != possibleValues.end());
+ possibleValues.erase(it);
+ }
+
+ // check second transaction items
+ items = second.getItems();
+ CPPUNIT_ASSERT(items.size() == 1);
+ for (auto item : items) {
+ auto kernel = std::dynamic_pointer_cast< RPMItem >(item->getItem());
+ CPPUNIT_ASSERT(kernel->getName() == "kernel");
+ CPPUNIT_ASSERT(kernel->getEpoch() == 0);
+ CPPUNIT_ASSERT(kernel->getVersion() == "4.11");
+ CPPUNIT_ASSERT(kernel->getRelease() == "301.fc26");
+
+ CPPUNIT_ASSERT(item->getAction() == TransactionItemAction::INSTALL);
+ CPPUNIT_ASSERT(item->getReason() == TransactionItemReason::DEPENDENCY);
+ CPPUNIT_ASSERT(item->getState() == TransactionItemState::DONE);
+ }
+
+ swdb->backup("sql.db");
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_RPMITEM_TEST_HPP
+#define LIBDNF_SWDB_RPMITEM_TEST_HPP
+
+#include "libdnf/transaction/Transformer.hpp"
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class TransformerMock : protected libdnf::Transformer {
+public:
+ TransformerMock();
+ using libdnf::Transformer::Exception;
+ using libdnf::Transformer::processGroupPersistor;
+ using libdnf::Transformer::transformTrans;
+};
+
+class TransformerTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(TransformerTest);
+ CPPUNIT_TEST(testGroupTransformation);
+ CPPUNIT_TEST(testTransformTrans);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testTransformTrans();
+ void testGroupTransformation();
+
+protected:
+ TransformerMock transformer;
+ std::shared_ptr< SQLite3 > swdb;
+ std::shared_ptr< SQLite3 > history;
+};
+
+#endif // LIBDNF_SWDB_RPMITEM_TEST_HPP
--- /dev/null
+#include <cstdio>
+#include <iostream>
+#include <string>
+
+#include "../backports.hpp"
+
+#include "libdnf/transaction/CompsEnvironmentItem.hpp"
+#include "libdnf/transaction/CompsGroupItem.hpp"
+#include "libdnf/transaction/RPMItem.hpp"
+#include "libdnf/transaction/Transaction.hpp"
+#include "libdnf/transaction/TransactionItem.hpp"
+#include "libdnf/transaction/Transformer.hpp"
+#include "libdnf/transaction/Types.hpp"
+
+#include "WorkflowTest.hpp"
+
+using namespace libdnf;
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WorkflowTest);
+
+void
+WorkflowTest::setUp()
+{
+ conn = std::make_shared< SQLite3 >(":memory:");
+ Transformer::createDatabase(conn);
+}
+
+void
+WorkflowTest::tearDown()
+{
+}
+
+void
+WorkflowTest::testDefaultWorkflow()
+{
+ // TODO: init/begin/end trans
+
+ // STEP 1: create transaction object
+ libdnf::swdb_private::Transaction trans(conn);
+ CPPUNIT_ASSERT_EQUAL(TransactionState::UNKNOWN, trans.getState());
+
+ // STEP 2: set vars
+ trans.setReleasever("26");
+
+ // populate goal
+ // resolve dependencies
+ // prepare RPM transaction
+
+ // STEP 3: associate RPMs to the transaction
+ // bash-4.4.12-5.fc26.x86_64
+ auto rpm_bash = std::make_shared< RPMItem >(conn);
+ rpm_bash->setName("bash");
+ rpm_bash->setEpoch(0);
+ rpm_bash->setVersion("4.4.12");
+ rpm_bash->setRelease("5.fc26");
+ rpm_bash->setArch("x86_64");
+ std::string repoid = "base";
+ TransactionItemAction action = TransactionItemAction::INSTALL;
+ TransactionItemReason reason = TransactionItemReason::GROUP;
+ trans.addItem(rpm_bash, repoid, action, reason);
+
+ // systemd-233-6.fc26
+ auto rpm_systemd = std::make_shared< RPMItem >(conn);
+ rpm_systemd->setName("systemd");
+ rpm_systemd->setEpoch(0);
+ rpm_systemd->setVersion("233");
+ rpm_systemd->setRelease("6.fc26");
+ rpm_systemd->setArch("x86_64");
+ repoid = "base";
+ action = TransactionItemAction::OBSOLETE;
+ reason = TransactionItemReason::USER;
+ auto ti_rpm_systemd = trans.addItem(rpm_systemd, repoid, action, reason);
+
+ // sysvinit-2.88-14.dsf.fc20
+ auto rpm_sysvinit = std::make_shared< RPMItem >(conn);
+ rpm_sysvinit->setName("sysvinit");
+ rpm_sysvinit->setEpoch(0);
+ rpm_sysvinit->setVersion("2.88");
+ rpm_sysvinit->setRelease("14.dsf.fc20");
+ rpm_sysvinit->setArch("x86_64");
+ repoid = "f20";
+ action = TransactionItemAction::OBSOLETED;
+ reason = TransactionItemReason::USER;
+ auto ti_rpm_sysvinit = trans.addItem(rpm_sysvinit, repoid, action, reason);
+ ti_rpm_sysvinit->addReplacedBy(ti_rpm_systemd);
+
+ auto comps_group_core = std::make_shared< CompsGroupItem >(conn);
+ comps_group_core->setGroupId("core");
+ comps_group_core->setName("Core");
+ comps_group_core->setTranslatedName("Úplný základ");
+ comps_group_core->addPackage("bash", true, CompsPackageType::MANDATORY);
+ repoid = "";
+ action = TransactionItemAction::INSTALL;
+ reason = TransactionItemReason::USER;
+ trans.addItem(comps_group_core, repoid, action, reason);
+
+ auto comps_environment_minimal = std::make_shared< CompsEnvironmentItem >(conn);
+ comps_environment_minimal->setEnvironmentId("minimal");
+ comps_environment_minimal->setName("Minimal");
+ comps_environment_minimal->setTranslatedName("mmm");
+ comps_environment_minimal->addGroup("core", true, CompsPackageType::MANDATORY);
+ repoid = "";
+ action = TransactionItemAction::INSTALL;
+ reason = TransactionItemReason::USER;
+ trans.addItem(comps_environment_minimal, repoid, action, reason);
+
+ // STEP 4: save transaction and all associated items
+ trans.begin();
+
+ // STEP 5: run RPM transaction; callback: mark completed items
+ for (auto i : trans.getItems()) {
+ i->setState(TransactionItemState::DONE);
+ i->save();
+ }
+
+ // STEP 6
+ // mark completed transaction
+ trans.finish(TransactionState::DONE);
+ CPPUNIT_ASSERT_EQUAL(TransactionState::DONE, trans.getState());
+
+ // VERIFY
+ // verify that data is available via public API
+ auto trans2 = libdnf::Transaction(conn, trans.getId());
+ CPPUNIT_ASSERT_EQUAL(TransactionState::DONE, trans2.getState());
+
+ CPPUNIT_ASSERT(trans2.getItems().size() == 5);
+
+ for (auto i : trans2.getItems()) {
+ if (i->getId() == 1) {
+ CPPUNIT_ASSERT(i->getAction() == TransactionItemAction::INSTALL);
+ CPPUNIT_ASSERT(i->getReason() == TransactionItemReason::GROUP);
+ CPPUNIT_ASSERT(i->getRepoid() == "base");
+ } else if (i->getId() == 2) {
+ CPPUNIT_ASSERT(i->getAction() == TransactionItemAction::OBSOLETE);
+ CPPUNIT_ASSERT(i->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(i->getRepoid() == "base");
+ } else if (i->getId() == 3) {
+ CPPUNIT_ASSERT(i->getAction() == TransactionItemAction::OBSOLETED);
+ CPPUNIT_ASSERT(i->getReason() == TransactionItemReason::USER);
+ CPPUNIT_ASSERT(i->getRepoid() == "f20");
+ }
+
+ // CPPUNIT_ASSERT(i->getItem()->getItemType() == "rpm");
+ CPPUNIT_ASSERT_EQUAL(TransactionItemState::DONE, i->getState());
+ // std::cout << "TransactionItem: " << i->getItem()->toStr() << std::endl;
+ if (i->getItem()->getItemType() == ItemType::GROUP) {
+ auto grp = std::dynamic_pointer_cast< CompsGroupItem >(i->getItem());
+ CPPUNIT_ASSERT(grp->getPackages().size() == 1);
+ for (auto i : grp->getPackages()) {
+ // std::cout << " CompsGroupPackage: " << i->getName() << std::endl;
+ }
+ }
+ if (i->getItem()->getItemType() == ItemType::ENVIRONMENT) {
+ auto env = std::dynamic_pointer_cast< CompsEnvironmentItem >(i->getItem());
+ CPPUNIT_ASSERT(env->getGroups().size() == 1);
+ for (auto i : env->getGroups()) {
+ // std::cout << " CompsEnvironmentGroup: @" << i->getGroupId() << std::endl;
+ }
+ }
+ }
+}
--- /dev/null
+#ifndef LIBDNF_SWDB_WORKFLOW_TEST_HPP
+#define LIBDNF_SWDB_WORKFLOW_TEST_HPP
+
+#include <cppunit/TestCase.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "libdnf/utils/sqlite3/Sqlite3.hpp"
+
+class WorkflowTest : public CppUnit::TestCase {
+ CPPUNIT_TEST_SUITE(WorkflowTest);
+ CPPUNIT_TEST(testDefaultWorkflow);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp() override;
+ void tearDown() override;
+
+ void testDefaultWorkflow();
+
+private:
+ std::shared_ptr< SQLite3 > conn;
+};
+
+#endif // LIBDNF_SWDB_WORKFLOW_TEST_HPP
--- /dev/null
+R"**(
+{
+ "meta" : {
+ "version" : "0.6.0"
+ },
+ "ENVIRONMENTS" : {
+ "minimal-environment" : {
+ "pkg_types" : 14,
+ "grp_types" : 15,
+ "ui_name" : "Minimálna inštalácia",
+ "name" : "Minimal Install",
+ "pkg_exclude" : [],
+ "full_list" : [
+ "core"
+ ]
+ }
+ },
+ "GROUPS" : {
+ "core" : {
+ "pkg_types" : 1,
+ "name" : "Core",
+ "pkg_exclude" : [],
+ "full_list" : [
+ "dnf-yum"
+ ],
+ "grp_types" : 0,
+ "ui_name" : "Úplný základ"
+ }
+ }
+}
+)**"
--- /dev/null
+R"**(
+ CREATE TABLE pkgtups (
+ pkgtupid INTEGER PRIMARY KEY,
+ name TEXT NOT NULL,
+ arch TEXT NOT NULL,
+ epoch TEXT NOT NULL,
+ version TEXT NOT NULL,
+ release TEXT NOT NULL,
+ checksum TEXT
+ );
+ CREATE TABLE trans_beg (
+ tid INTEGER PRIMARY KEY,
+ timestamp INTEGER NOT NULL,
+ rpmdb_version TEXT NOT NULL,
+ loginuid INTEGER
+ );
+ CREATE TABLE trans_end (
+ tid INTEGER PRIMARY KEY REFERENCES trans_beg,
+ timestamp INTEGER NOT NULL,
+ rpmdb_version TEXT NOT NULL,
+ return_code INTEGER NOT NULL
+ );
+ CREATE TABLE trans_cmdline (
+ tid INTEGER NOT NULL REFERENCES trans_beg,
+ cmdline TEXT NOT NULL
+ );
+ CREATE TABLE trans_data_pkgs (
+ tid INTEGER NOT NULL REFERENCES trans_beg,
+ pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
+ done BOOL NOT NULL DEFAULT FALSE, state TEXT NOT NULL
+ );
+ CREATE TABLE trans_script_stdout (
+ lid INTEGER PRIMARY KEY,
+ tid INTEGER NOT NULL REFERENCES trans_beg,
+ line TEXT NOT NULL
+ );
+ CREATE TABLE pkg_yumdb (
+ pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
+ yumdb_key TEXT NOT NULL,
+ yumdb_val TEXT NOT NULL
+ );
+ CREATE TABLE trans_with_pkgs (
+ tid INTEGER NOT NULL REFERENCES trans_beg,
+ pkgtupid INTEGER NOT NULL REFERENCES pkgtups
+ );
+ CREATE TABLE trans_error (
+ mid INTEGER PRIMARY KEY,
+ tid INTEGER NOT NULL REFERENCES trans_beg,
+ msg TEXT NOT NULL
+ );
+
+ /* Initialize the history database */
+
+ INSERT INTO
+ pkgtups
+ VALUES
+ (1, 'chrony', 'x86_64', 1, '3.1', '4.fc26', 'sha256:6cec2091'),
+ (2, 'kernel', 'x86_64', 0, '4.11', '301.fc26', 'sha256:8dc6bb96'),
+ (3, 'chrony', 'x86_64', 1, '3.2', '4.fc26', 'sha256:6asd1231');
+
+ INSERT INTO
+ pkg_yumdb
+ VALUES
+ (1, 'releasever', '26'),
+ (1, 'reason', 'user'),
+ (2, 'releasever', 'rawhide'),
+ (2, 'reason', 'dep'),
+ (3, 'releasever', '26'),
+ (3, 'reason', 'user');
+
+ INSERT INTO
+ trans_beg
+ VALUES
+ (1, 1513267401, '2213:9795b6a4db5e5368628b5240ec63a629833c5594', 1000),
+ (2, 1513267535, '2213:9eab991133c166f8bcf3ecea9fb422b853f7aebc', 1000);
+
+ INSERT INTO
+ trans_end
+ VALUES
+ (1, 1513267509, '2213:9eab991133c166f8bcf3ecea9fb422b853f7aebc', 0),
+ (2, 1513267539, '2214:e02004142740afb5b6d148d50bc84be4ab41ad13', 0);
+
+ INSERT INTO
+ trans_cmdline
+ VALUES
+ (1, 'upgrade -y'),
+ (2, '-y install Foo');
+
+ INSERT INTO
+ trans_script_stdout
+ VALUES
+ (1, 1, 'line1'),
+ (2, 1, 'line2');
+
+ INSERT INTO
+ trans_error
+ VALUES
+ (1, 2, 'msg1'),
+ (2, 2, 'msg2');
+
+ INSERT INTO
+ trans_data_pkgs
+ VALUES
+ (1, 3, 'TRUE', 'Update'),
+ (1, 1, 'TRUE', 'Updated'),
+ (2, 2, 'TRUE', 'Install');
+
+ INSERT INTO
+ trans_with_pkgs
+ VALUES
+ (1,1),
+ (2,1),
+ (2,2);
+)**"
--- /dev/null
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+int main(int argc, char *argv[])
+{
+ CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
+
+ CppUnit::TextUi::TestRunner runner;
+ runner.addTest(suite);
+
+ runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(), std::cerr));
+
+ return runner.run() ? 0 : 1;
+}