Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error messages for system state loading #1623

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dnf5.spec
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down
1 change: 1 addition & 0 deletions doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions doc/conf.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -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),
jan-kolarik marked this conversation as resolved.
Show resolved Hide resolved
('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),
Expand Down
10 changes: 3 additions & 7 deletions doc/dnf5.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -456,16 +456,12 @@ Miscellaneous:
| :manpage:`dnf5-aliases(7)`, :ref:`Aliases for command line arguments <aliases_misc_ref-label>`
| :manpage:`dnf5-caching(7)`, :ref:`Caching <caching_misc_ref-label>`
| :manpage:`dnf5-comps(7)`, :ref:`Comps groups and environments <comps_misc_ref-label>`
| :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, <filtering_misc_ref-label>`
| :manpage:`dnf5-forcearch(7)`, :ref:`Forcearch parameter <forcearch_misc_ref-label>`
| :manpage:`dnf5-installroot(7)`, :ref:`Installroot parameter <installroot_misc_ref-label>`
| :manpage:`dnf5-specs(7)`, :ref:`Patterns specification <specs_misc_ref-label>`

..
# TODO(jkolarik): Filtering is not ready yet
| :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, <filtering_misc_ref-label>`

# TODO(jkolarik): Modularity is not ready yet
| :manpage:`dnf5-modularity(7)`, :ref:`Modularity overview, <modularity_misc_ref-label>`
| :manpage:`dnf5-specs(7)`, :ref:`Patterns specification <specs_misc_ref-label>`
| :manpage:`dnf5-system-state(7)`, :ref:`System state <systemstate_misc_ref-label>`

Project homepage:
| https://github.com/rpm-software-management/dnf5
11 changes: 8 additions & 3 deletions doc/dnf5.conf.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -431,15 +431,20 @@ repository configuration file should aside from repo ID consists of baseurl, met

:ref:`string <string-label>`

For superuser overwrites the :ref:`cachedir <_cachedir_options-label>` option value.
For superuser overwrites the :ref:`cachedir <cachedir_options-label>` 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 <string-label>`

System state files location. See :manpage:`dnf5-system-state(7)`, :ref:`system state <systemstate_misc_ref-label>` for details.

Default: ``/usr/lib/sysimage/libdnf5``.

.. _tsflags_options-label:

Expand Down
1 change: 1 addition & 0 deletions doc/misc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Miscellaneous
installroot.7
modularity.7
specs.7
system-state.7
44 changes: 44 additions & 0 deletions doc/misc/system-state.7.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
..
jan-kolarik marked this conversation as resolved.
Show resolved Hide resolved
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 <https://www.gnu.org/licenses/>.

.. _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 <system_state_dir_options-label>`). 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.
34 changes: 26 additions & 8 deletions libdnf5/system/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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<std::string>(toml_value, "version");
auto version_parsed = parse_version(version_string);
Expand All @@ -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<std::map<std::string, PackageState>>(get_package_state_path(), "packages");
nevra_states = load_toml_data<std::map<std::string, NevraState>>(get_nevra_state_path(), "nevras");
group_states = load_toml_data<std::map<std::string, GroupState>>(get_group_state_path(), "groups");
environment_states =
load_toml_data<std::map<std::string, EnvironmentState>>(get_environment_state_path(), "environments");
std::string path;
try {
path = get_package_state_path();
package_states = load_toml_data<std::map<std::string, PackageState>>(path, "packages");
path = get_nevra_state_path();
nevra_states = load_toml_data<std::map<std::string, NevraState>>(path, "nevras");
path = get_group_state_path();
group_states = load_toml_data<std::map<std::string, GroupState>>(path, "groups");
path = get_environment_state_path();
environment_states = load_toml_data<std::map<std::string, EnvironmentState>>(path, "environments");
#ifdef WITH_MODULEMD
module_states = load_toml_data<std::map<std::string, ModuleState>>(get_module_state_path(), "modules");
path = get_module_state_path();
module_states = load_toml_data<std::map<std::string, ModuleState>>(path, "modules");
#endif
system_state = load_toml_data<SystemState>(get_system_state_path(), "system");
path = get_system_state_path();
system_state = load_toml_data<SystemState>(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();
}

Expand Down
8 changes: 8 additions & 0 deletions libdnf5/system/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading