From 9dc293471cefba8cd9679cf390e2a9acc09432fa Mon Sep 17 00:00:00 2001 From: finkandreas Date: Tue, 13 Feb 2024 09:35:29 +0100 Subject: [PATCH] propagate errors (#15) This PR fixes errror propagation. At the moment commands like `uenv run store.squashfs -- my_cmd` will always look successful, independent of the status of `my_cmd`. With this PR it will be possible to propaget the error, and chain commands in the shell with `&&` or `||`. There is a tight integration of `uenv-impl` and the `uenv` function, because `uenv-impl` sets variables that will be returned from the `uenv` function. This is not great, but I could not figure out a way how else I could make it happen. Here are two examples that would work with the suggested changes: ```bash if uenv run store.squashfs -- false ; then echo "Success status" else echo "Failure status" ``` and also ```bash if uenv start store.squashfs ; then echo "Success status" else echo "Failure status" fi ``` The latter will have the exit status of the last run command, which is the default behaviour for subshells, where the last command's exit status defines the subshell's exit status. --- activate | 3 +++ uenv-impl | 28 ++++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/activate b/activate index 404b859..909e9d2 100644 --- a/activate +++ b/activate @@ -6,6 +6,8 @@ export UENV_CMD=@@impl@@ export UENV_VERSION=@@version@@ function uenv { + local _last_exitcode=$? + function uenv_usage { echo "uenv - for using user environments [version @@version@@]" echo "" @@ -31,6 +33,7 @@ function uenv { fi unset -f uenv_usage + return $_exitcode } export -f uenv diff --git a/uenv-impl b/uenv-impl index 295f972..8f2fe5f 100755 --- a/uenv-impl +++ b/uenv-impl @@ -15,6 +15,7 @@ import subprocess VERSION="@@version@@" shell_noop=" :" +shell_error="local _exitcode=1" def make_argparser(): parser = argparse.ArgumentParser() @@ -384,7 +385,7 @@ def generate_command(args): env = environment() if env.old_api: print_error(f"the version of squashfs-mount on this system is too old.") - return shell_noop + return shell_error if args.command == "run": return generate_run_command(args, env) @@ -400,7 +401,7 @@ def generate_command(args): return generate_modules_command(args, env) print_error(f"unknown command '{args.command}'") - return shell_noop + return shell_error """ uenv start gromacs.squashfs ddt.squashfs @@ -538,7 +539,7 @@ def generate_run_command(args, env): print_debug(f"parsing run command with arguments: {args.command}") if env.active: print_error("a uenv is already running") - return shell_noop + return shell_error images, cmd, cmdargs = split_runline(args.runline) @@ -548,7 +549,7 @@ def generate_run_command(args, env): mount_pairs=parse_image_descriptions(images) if mount_pairs==[]: - return shell_noop + return shell_error mount_string = ' '.join(mount_pairs) cmdargs_string = ' '.join([f'"{arg}"' for arg in cmdargs]) @@ -558,6 +559,7 @@ def generate_run_command(args, env): return [f"export UENV_MOUNT_FILE={main_mount[0]}", f"export UENV_MOUNT_POINT={main_mount[1]}", f"squashfs-mount {mount_string} -- {cmd} {cmdargs_string}", + 'local _exitcode=$?', "unset UENV_MOUNT_FILE; unset UENV_MOUNT_POINT;"] @@ -565,11 +567,11 @@ def generate_start_command(args, env): print_debug(f"parsing start command with arguments: {args.image}") if env.active: print_error("a uenv is already running") - return shell_noop + return shell_error mount_pairs=parse_image_descriptions(args.image) if mount_pairs==[]: - return shell_noop + return shell_error mount_string = ' '.join(mount_pairs) @@ -578,6 +580,7 @@ def generate_start_command(args, env): return [f"export UENV_MOUNT_FILE={main_mount[0]}", f"export UENV_MOUNT_POINT={main_mount[1]}", f"squashfs-mount {mount_string} -- bash", + "local _exitcode=$?", "unset UENV_MOUNT_FILE; unset UENV_MOUNT_POINT;"] def generate_modules_command(args, env): @@ -586,7 +589,7 @@ def generate_modules_command(args, env): if not env.active: print_error(f'there is no environment loaded') - return shell_noop + return shell_error # generate a list of all the mounted environments that provide modules module_envs = [ @@ -631,7 +634,7 @@ def generate_modules_command(args, env): and (e.is_native_mounted)] if len(matches)==0: print_error(f"no uenv matching {i} provides modules") - return shell_noop + return shell_error print_debug(f" uenv {i} mounted at {matches[0]}") mounts.append(matches[0]) @@ -649,11 +652,11 @@ def generate_view_command(args, env): if not env.active: print_error(f'there is no environment loaded') - return shell_noop + return shell_error if env.loaded_view is not None: print_error(f'a view is already loaded: {env.loaded_view}') - return shell_noop + return shell_error uenv = env.uenvs[0] name = args.view_name @@ -668,6 +671,7 @@ def generate_view_command(args, env): f"export UENV_VIEW={uenv.mount}:{name}",] else: print_error(f'the view "{name}" is not one of the available views: {available_views}') + return shell_error return shell_noop @@ -734,9 +738,9 @@ def generate_stop_command(args, env): if not env.active: print_error(f"there is no running environment to stop") - return shell_noop + return shell_error - return "exit 0" + return "exit $_last_exitcode" if __name__ == "__main__":