Improve error reporting

This commit is contained in:
Kivi Kaitaniemi
2024-04-26 14:43:52 +03:00
parent c97587b3f5
commit fa6aee8d66
3 changed files with 86 additions and 50 deletions
+24 -17
View File
@@ -23,33 +23,35 @@ def sh(sh_cmd: str,
env = os.environ.copy()
for var, val in env_overrides.items():
env[var] = val
try:
if user is None:
try:
subprocess.run(sh_cmd, shell=True, check=True, env=env)
except subprocess.CalledProcessError as e:
raise decman.error.UserFacingError(
f"Running user defined shell command '{sh_cmd}' failed."
) from e
else:
try:
uid = pwd.getpwnam(user).pw_uid
gid = pwd.getpwnam(user).pw_gid
except KeyError as e:
raise decman.error.UserFacingError(
f"Running user defined shell command failed because the user {user} doesn't exist."
) from e
with subprocess.Popen(sh_cmd,
shell=True,
group=gid,
user=uid,
with subprocess.Popen(sh_cmd, shell=True, group=gid, user=uid,
env=env) as process:
if process.wait() != 0:
raise decman.error.UserFacingError(
f"Running user shell command '{sh_cmd}' as {user} failed."
)
except (subprocess.CalledProcessError, KeyError) as e:
raise decman.error.UserFacingError(
f"Running user shell command '{sh_cmd}' failed.") from e
f"Running user shell command '{sh_cmd}' as {user} failed.")
def cmd(command: list[str],
def prg(command: list[str],
user: typing.Optional[str] = None,
env_overrides: typing.Optional[dict[str, str]] = None):
"""
Shortcut for running a command.
Shortcut for running a program.
"""
if env_overrides is None:
env_overrides = {}
@@ -58,21 +60,26 @@ def cmd(command: list[str],
for var, val in env_overrides.items():
env[var] = val
try:
if user is None:
try:
subprocess.run(command, check=True, env=env)
except subprocess.CalledProcessError as e:
raise decman.error.UserFacingError(
f"Running user defined program '{command}' failed.") from e
else:
try:
uid = pwd.getpwnam(user).pw_uid
gid = pwd.getpwnam(user).pw_gid
except KeyError as e:
raise decman.error.UserFacingError(
f"Running user defined program failed because the user {user} doesn't exist."
) from e
with subprocess.Popen(command, group=gid, user=uid,
env=env) as process:
if process.wait() != 0:
raise decman.error.UserFacingError(
f"Running user command '{command}' as {user} failed.")
except (subprocess.CalledProcessError, KeyError) as e:
raise decman.error.UserFacingError(
f"Running user command '{command}' failed.") from e
f"Running user program '{command}' as {user} failed.")
class File:
+30 -15
View File
@@ -182,7 +182,8 @@ class Store:
with open(path, "wt", encoding="utf-8") as file:
json.dump(d, file)
except OSError as e:
raise err.UserFacingError("Failed to save store.") from e
print_error(f"{e}")
raise err.UserFacingError("Failed to save decman store.") from e
@staticmethod
def restore() -> "Store":
@@ -220,9 +221,13 @@ class Store:
return store
except json.JSONDecodeError as e:
raise err.UserFacingError("Failed to parse state json.") from e
print_error(f"{e}")
raise err.UserFacingError(
"Failed to parse decman store json.") from e
except OSError as e:
raise err.UserFacingError("Failed to read saved store.") from e
print_error(f"{e}")
raise err.UserFacingError(
"Failed to read saved decman store.") from e
class Source:
@@ -302,6 +307,7 @@ class Source:
file.copy_to(target, variables)
print_debug(f"Installing file to {target}.")
except OSError as e:
print_error(f"{e}")
raise err.UserFacingError(
f"Failed to install file to {target}.") from e
@@ -312,6 +318,7 @@ class Source:
print_debug(f"Installing directory to {target}.")
directory.copy_to(target, variables)
except OSError as e:
print_error(f"{e}")
raise err.UserFacingError(
f"Failed to install directory to {target}.") from e
@@ -543,7 +550,7 @@ class Pacman:
for line in output]
except IndexError as error:
raise err.UserFacingError(
f"Failed to get foreign packages from pacman output. Output: {output}"
f"Failed to parse foreign packages from pacman output. Output: {output}"
) from error
def install(self, packages: list[str]):
@@ -553,7 +560,8 @@ class Pacman:
try:
subprocess.run(conf.commands.install_pkgs(packages), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError("Failed to install packages.") from error
raise err.UserFacingError(
"Failed to install packages using pacman.") from error
def install_dependencies(self, deps: list[str]):
"""
@@ -563,7 +571,8 @@ class Pacman:
subprocess.run(conf.commands.install_deps(deps), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError(
"Failed to install dependency packages.") from error
"Failed to install packages as dependencies using pacman."
) from error
def install_files(self, files: list[str], as_explicit: list[str]):
"""
@@ -577,8 +586,11 @@ class Pacman:
check=True,
capture_output=conf.suppress_command_output)
except subprocess.CalledProcessError as error:
if conf.suppress_command_output:
print_error("Output:")
print_continuation(error.output)
raise err.UserFacingError(
"Failed to install foreign packages.") from error
"Failed to install package files using pacman.") from error
def upgrade(self):
"""
@@ -587,7 +599,8 @@ class Pacman:
try:
subprocess.run(conf.commands.upgrade(), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError("Failed to update packages.") from error
raise err.UserFacingError(
"Failed to upgrade packages using pacman.") from error
def remove(self, packages: list[str]):
"""
@@ -596,7 +609,8 @@ class Pacman:
try:
subprocess.run(conf.commands.remove(packages), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError("Failed to remove packages.") from error
raise err.UserFacingError(
"Failed to remove packages using pacman.") from error
class Systemd:
@@ -615,7 +629,7 @@ class Systemd:
subprocess.run(conf.commands.enable_units(units), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError(
"Failed to enable systemd units.") from error
f"Failed to enable systemd units: {units}") from error
self.state.enabled_systemd_units += units
def disable_units(self, units: list[str]):
@@ -626,7 +640,7 @@ class Systemd:
subprocess.run(conf.commands.disable_units(units), check=True)
except subprocess.CalledProcessError as error:
raise err.UserFacingError(
"Failed to disable systemd units.") from error
f"Failed to disable systemd units: {units}") from error
for unit in units:
try:
self.state.enabled_systemd_units.remove(unit)
@@ -646,10 +660,10 @@ class Systemd:
user=uid) as process:
if process.wait() != 0:
raise err.UserFacingError(
f"Failed to enable systemd units for {user}.")
f"Failed to enable systemd units: {units} for {user}.")
except KeyError as error:
raise err.UserFacingError(
f"Failed to enable systemd units because user '{user}' doesn't exist."
f"Failed to enable systemd units because user {user} doesn't exist."
) from error
for unit in units:
self.state.enabled_user_systemd_units.append((user, unit))
@@ -667,10 +681,11 @@ class Systemd:
user=uid) as process:
if process.wait() != 0:
raise err.UserFacingError(
f"Failed to disable systemd units for {user}.")
f"Failed to disable systemd units: {units} for {user}."
)
except KeyError as error:
raise err.UserFacingError(
f"Failed to disable systemd units because user '{user}' doesn't exist."
f"Failed to disable systemd units because user {user} doesn't exist."
) from error
for unit in units:
+21 -7
View File
@@ -324,8 +324,10 @@ class ExtendedPackageSearch:
l.print_debug("Request completed.")
except (requests.RequestException, KeyError) as e:
l.print_error(f"{e}")
raise err.UserFacingError(
"Failed to fetch package information from AUR RPC.") from e
f"Failed to fetch package information for {packages} from AUR RPC."
) from e
def get_package_info(self, package: str) -> typing.Optional[PackageInfo]:
"""
@@ -379,8 +381,10 @@ class ExtendedPackageSearch:
return info
except (requests.RequestException, KeyError) as e:
l.print_error(f"{e}")
raise err.UserFacingError(
"Failed to fetch package information from AUR RPC.") from e
f"Failed to fetch package information for {package} from AUR RPC."
) from e
def find_provider(
self, stripped_dependency: str) -> typing.Optional[PackageInfo]:
@@ -452,8 +456,10 @@ class ExtendedPackageSearch:
return self._choose_provider(stripped_dependency, results, "AUR")
except (requests.RequestException, KeyError) as e:
l.print_error(f"{e}")
raise err.UserFacingError(
"Failed to fetch package information from AUR RPC.") from e
f"Failed to search for {stripped_dependency} from AUR RPC."
) from e
def _choose_provider(self, dep: str, possible_providers: list[str],
where: str) -> typing.Optional[PackageInfo]:
@@ -569,7 +575,9 @@ class ForeignPackageManager:
info = self._search.get_package_info(pkg)
if info is None:
raise err.UserFacingError(f"Failed to find package: {pkg}.")
raise err.UserFacingError(
f"Failed to find '{pkg}' from AUR or user provided packages."
)
if self.should_upgrade_package(pkg, ver, info.version,
upgrade_devel):
@@ -650,6 +658,7 @@ class ForeignPackageManager:
builder.build_packages(pkgbase, packages, force)
except (subprocess.CalledProcessError, OSError) as e:
l.print_error(f"{e}")
raise err.UserFacingError("Failed to build packages.") from e
packages_to_install = list(resolved_dependencies.foreign_pkgs)
@@ -792,7 +801,9 @@ class ForeignPackageManager:
)
return should_upgrade
except (ValueError, subprocess.CalledProcessError) as error:
raise err.UserFacingError("Failed to compare versions.") from error
l.print_error(f"{error}")
raise err.UserFacingError(
"Failed to compare versions using vercmp.") from error
class PackageBuilder:
@@ -1031,7 +1042,7 @@ class PackageBuilder:
for foreign_pkg in chroot_foreign_pkgs:
entry = self._store.get_package(foreign_pkg)
assert entry is not None, "Build order determines that the dependencies are built \
before and thus are found in the cache."
before and thus are found in the cache."
_, file = entry
@@ -1058,7 +1069,7 @@ class PackageBuilder:
if len(matches) != 1:
raise err.UserFacingError(
f"Failed to build package '{pkgname}', because the pkg file cannot be determined."
f"Failed to build package '{pkgname}', because the pkg file cannot be determined. Possible files are: {matches}"
)
return matches[0]
@@ -1100,6 +1111,9 @@ class PackageBuilder:
raise err.UserFacingError("Building aborted.")
except subprocess.CalledProcessError as error:
if conf.suppress_command_output:
l.print_error("Output:")
l.print_continuation(error.output)
raise err.UserFacingError(
f"Failed to clone and review PKGBUILD from {git_url}"
) from error