diff --git a/dnf5.spec b/dnf5.spec index 06423f02b..52f23b0b9 100644 --- a/dnf5.spec +++ b/dnf5.spec @@ -335,6 +335,7 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %{_mandir}/man7/dnf*-installroot.7.* %{_mandir}/man7/dnf*-modularity.7.* %{_mandir}/man7/dnf*-specs.7.* +%{_mandir}/man7/dnf*-system-state.7.* %{_mandir}/man5/dnf*.conf.5.* %{_mandir}/man5/dnf*.conf-todo.5.* %{_mandir}/man5/dnf*.conf-deprecated.5.* diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 90d728654..19a1855a6 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -93,6 +93,7 @@ if(WITH_MAN) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-installroot.7 DESTINATION share/man/man7) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-modularity.7 DESTINATION share/man/man7) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-specs.7 DESTINATION share/man/man7) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-system-state.7 DESTINATION share/man/man7) # plugin commands install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-automatic.8 DESTINATION share/man/man8) diff --git a/doc/conf.py.in b/doc/conf.py.in index 7d97ff599..eb3e7c508 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -158,6 +158,7 @@ man_pages = [ ('misc/installroot.7', 'dnf5-installroot', 'Installroot Parameter', AUTHORS, 7), ('misc/modularity.7', 'dnf5-modularity', 'Modularity Overview', AUTHORS, 7), ('misc/specs.7', 'dnf5-specs', 'Patterns Specification', AUTHORS, 7), + ('misc/system-state.7', 'dnf5-system-state', 'System state', AUTHORS, 7), ('dnf_daemon/dnf5daemon_client.8', 'dnf5daemon-client', 'Command-line interface for Dnf5daemon', AUTHORS, 8), ('dnf_daemon/dnf5daemon_server.8', 'dnf5daemon-server', 'Package management service with a DBus interface', AUTHORS, 8), ('dnf_daemon/dnf5daemon_dbus_api.8', 'dnf5daemon-dbus-api', 'DBus API Reference for Dnf5daemon', AUTHORS, 8), diff --git a/doc/dnf5.8.rst b/doc/dnf5.8.rst index 19edb7f66..7064957b3 100644 --- a/doc/dnf5.8.rst +++ b/doc/dnf5.8.rst @@ -456,16 +456,12 @@ Miscellaneous: | :manpage:`dnf5-aliases(7)`, :ref:`Aliases for command line arguments ` | :manpage:`dnf5-caching(7)`, :ref:`Caching ` | :manpage:`dnf5-comps(7)`, :ref:`Comps groups and environments ` + | :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, ` | :manpage:`dnf5-forcearch(7)`, :ref:`Forcearch parameter ` | :manpage:`dnf5-installroot(7)`, :ref:`Installroot parameter ` - | :manpage:`dnf5-specs(7)`, :ref:`Patterns specification ` - -.. - # TODO(jkolarik): Filtering is not ready yet - | :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, ` - - # TODO(jkolarik): Modularity is not ready yet | :manpage:`dnf5-modularity(7)`, :ref:`Modularity overview, ` + | :manpage:`dnf5-specs(7)`, :ref:`Patterns specification ` + | :manpage:`dnf5-system-state(7)`, :ref:`System state ` Project homepage: | https://github.com/rpm-software-management/dnf5 diff --git a/doc/dnf5.conf.5.rst b/doc/dnf5.conf.5.rst index 3b95f7080..fdd5c9e07 100644 --- a/doc/dnf5.conf.5.rst +++ b/doc/dnf5.conf.5.rst @@ -431,15 +431,20 @@ repository configuration file should aside from repo ID consists of baseurl, met :ref:`string ` - For superuser overwrites the :ref:`cachedir <_cachedir_options-label>` option value. + For superuser overwrites the :ref:`cachedir ` option value. Allows to differentiate user and superuser cachedir. Default: ``/var/cache/libdnf5``. -.. _system_state_options-label: +.. _system_state_dir_options-label: -``system_state`` +``system_state_dir`` + :ref:`string ` + + System state files location. See :manpage:`dnf5-system-state(7)`, :ref:`system state ` for details. + + Default: ``/usr/lib/sysimage/libdnf5``. .. _tsflags_options-label: diff --git a/doc/misc/index.rst b/doc/misc/index.rst index 90daf25bb..3d8b617c9 100644 --- a/doc/misc/index.rst +++ b/doc/misc/index.rst @@ -14,3 +14,4 @@ Miscellaneous installroot.7 modularity.7 specs.7 + system-state.7 diff --git a/doc/misc/system-state.7.rst b/doc/misc/system-state.7.rst new file mode 100644 index 000000000..7e9421cb5 --- /dev/null +++ b/doc/misc/system-state.7.rst @@ -0,0 +1,44 @@ +.. + Copyright Contributors to the libdnf project. + + This file is part of libdnf: https://github.com/rpm-software-management/libdnf/ + + Libdnf is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Libdnf is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty 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 libdnf. If not, see . + +.. _systemstate_misc_ref-label: + +############## + System state +############## + +Description +=========== + +The DNF5 system state consists of several TOML files with their location determined by the `system_state_dir` configuration option (:manpage:`dnf5-conf(5)`, :ref:`system_state_dir `). DNF5 uses the system state to: + + 1. Store the reasons why each installed package was added to the system. The reasons can be "user" for packages that the user explicitly asked DNF5 to install, "dependency" and "weak dependency" for packages pulled in as dependencies of another package, "group" for packages installed by a group, or "external" for packages installed by another tool (e.g. rpm). + + 2. Track installed groups and packages installed by these groups. + + 3. Track installed environmental groups. + + +The way of storing the DNF5 system state is an internal implementation detail and may change at any time. To modify the state, always use the DNF5 command-line interface or DNF5 API. + + +Recovering from a corrupted system state +======================================== + +If the system state files become corrupted, simply back up and remove the corrupted TOML file mentioned in the error message. It will be regenerated during the next successful DNF5 transaction. +The regenerated files may lack some data, such as the reasons why packages were installed or the repositories from which they were installed. diff --git a/libdnf5/system/state.cpp b/libdnf5/system/state.cpp index 7cff97e0b..210d32076 100644 --- a/libdnf5/system/state.cpp +++ b/libdnf5/system/state.cpp @@ -297,6 +297,10 @@ StateNotFoundError::StateNotFoundError(const std::string & type, const std::stri : libdnf5::Error(M_("{} state for \"{}\" not found."), type, key) {} +StateLoadError::StateLoadError(const std::string & path, const std::string & error) + : libdnf5::Error(M_("Loading system state TOML file {} failed (see dnf5-system-state(7)): {}"), path, error) {} + + State::State(const std::filesystem::path & path) : path(path) { load(); } @@ -600,7 +604,7 @@ static T load_toml_data(const std::string & path, const std::string & key) { return {}; } - auto toml_value = toml::parse(path); + const auto toml_value = toml::parse(path); auto version_string = toml::find(toml_value, "version"); auto version_parsed = parse_version(version_string); @@ -616,15 +620,29 @@ static T load_toml_data(const std::string & path, const std::string & key) { void State::load() { - package_states = load_toml_data>(get_package_state_path(), "packages"); - nevra_states = load_toml_data>(get_nevra_state_path(), "nevras"); - group_states = load_toml_data>(get_group_state_path(), "groups"); - environment_states = - load_toml_data>(get_environment_state_path(), "environments"); + std::string path; + try { + path = get_package_state_path(); + package_states = load_toml_data>(path, "packages"); + path = get_nevra_state_path(); + nevra_states = load_toml_data>(path, "nevras"); + path = get_group_state_path(); + group_states = load_toml_data>(path, "groups"); + path = get_environment_state_path(); + environment_states = load_toml_data>(path, "environments"); #ifdef WITH_MODULEMD - module_states = load_toml_data>(get_module_state_path(), "modules"); + path = get_module_state_path(); + module_states = load_toml_data>(path, "modules"); #endif - system_state = load_toml_data(get_system_state_path(), "system"); + path = get_system_state_path(); + system_state = load_toml_data(path, "system"); + } catch (const InvalidVersionError & ex) { + throw; + } catch (const UnsupportedVersionError & ex) { + throw; + } catch (const std::exception & ex) { + throw StateLoadError(path, ex.what()); + } package_groups_cache.reset(); } diff --git a/libdnf5/system/state.hpp b/libdnf5/system/state.hpp index 8730e4c10..f410342b9 100644 --- a/libdnf5/system/state.hpp +++ b/libdnf5/system/state.hpp @@ -101,6 +101,14 @@ class UnsupportedVersionError : public libdnf5::Error { const char * get_name() const noexcept override { return "UnsupportedVersionError"; } }; +class StateLoadError : public libdnf5::Error { +public: + StateLoadError(const std::string & path, const std::string & error); + + const char * get_domain_name() const noexcept override { return "libdnf5::system"; } + const char * get_name() const noexcept override { return "StateLoadError"; } +}; + /// A class providing information and allowing modification of the DNF system /// state. The state consists of a list of userinstalled packages, installed