diff --git a/dnf/cli/cli.py b/dnf/cli/cli.py index 1824bd00ed..c14f836398 100644 --- a/dnf/cli/cli.py +++ b/dnf/cli/cli.py @@ -214,6 +214,15 @@ def do_transaction(self, display=()): elif 'test' in self.conf.tsflags: logger.info(_("{prog} will only download packages, install gpg keys, and check the " "transaction.").format(prog=dnf.util.MAIN_PROG_UPPER)) + if dnf.util.is_container(): + _container_msg = _(""" +*** This system is managed with ostree. Changes to the system +*** made with dnf will be lost with the next ostree-based update. +*** If you do not want to lose these changes, use 'rpm-ostree'. +""") + logger.info(_container_msg) + raise CliError(_("Operation aborted.")) + if self._promptWanted(): if self.conf.assumeno or not self.output.userconfirm(): raise CliError(_("Operation aborted.")) diff --git a/dnf/cli/commands/__init__.py b/dnf/cli/commands/__init__.py index 52e6a03391..11fa85b6ca 100644 --- a/dnf/cli/commands/__init__.py +++ b/dnf/cli/commands/__init__.py @@ -653,7 +653,6 @@ def configure(self): def run_on_repo(self): """Execute the command with respect to given arguments *cli_args*.""" - done = False if not self.opts.pkg_specs: diff --git a/dnf/cli/commands/reinstall.py b/dnf/cli/commands/reinstall.py index 2b3ceac7b3..39b8cda4c4 100644 --- a/dnf/cli/commands/reinstall.py +++ b/dnf/cli/commands/reinstall.py @@ -59,7 +59,6 @@ def configure(self): commands._checkEnabledRepo(self.base) def run(self): - # Reinstall files. done = False for pkg in self.base.add_remote_rpms(self.opts.filenames, strict=False, diff --git a/dnf/util.py b/dnf/util.py index 6cd7ad41fe..1b465bda59 100644 --- a/dnf/util.py +++ b/dnf/util.py @@ -33,11 +33,13 @@ import functools import hawkey import itertools +import json import locale import logging import os import pwd import shutil +import subprocess import sys import tempfile import time @@ -639,3 +641,32 @@ def _is_file_pattern_present(specs): if subj._filename_pattern: return True return False + + +def is_container(): + """Returns true is the system is managed as an immutable container, + false otherwise. If msg is True, a warning message is displayed + for the user. + """ + + bootc = '/usr/bin/bootc' + ostree = '/sysroot/ostree' + + if os.path.isfile(bootc) and os.access(bootc, os.X_OK): + p = subprocess.Popen([bootc, "status", "--json"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = p.communicate() + + if p.returncode == 0: + # check the output of 'bootc status' + j = json.loads(out) + + # XXX: the API from bootc status is evolving + status = j.get("status", "") + kind = j.get("kind", "") + + if kind.lower() == "bootchost" and bool(status.get("isContainer", None)): + return True + elif os.path.isdir(ostree): + return True + + return False