diff --git a/helpers/apps b/helpers/apps index 85b74de15..4b253ff90 100644 --- a/helpers/apps +++ b/helpers/apps @@ -111,3 +111,95 @@ ynh_remove_apps() { done fi } + +# Spawn a Bash shell with the app environment loaded +# +# usage: ynh_spawn_app_shell --app="app" +# | arg: -a, --app= - the app ID +# +# examples: +# ynh_spawn_app_shell --app="APP" <<< 'echo "$USER"' +# ynh_spawn_app_shell --app="APP" < /tmp/some_script.bash +# +# Requires YunoHost version 11.0.* or higher, and that the app relies on packaging v2 or higher. +# The spawned shell will have environment variables loaded and environment files sourced +# from the app's service configuration file (defaults to $app.service, overridable by the packager with `service` setting). +# If the app relies on a specific PHP version, then `php` will be aliased that version. +ynh_spawn_app_shell() { + # Declare an array to define the options of this helper. + local legacy_args=a + local -A args_array=([a]=app=) + local app + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + + # Force Bash to be used to run this helper + if [[ ! $0 =~ \/?bash$ ]] + then + ynh_print_err --message="Please use Bash as shell" + exit 1 + fi + + # Make sure the app is installed + local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id)) + if [[ " ${installed_apps_list[*]} " != *" ${app} "* ]] + then + ynh_print_err --message="$app is not in the apps list" + exit 1 + fi + + # Make sure the app has its own user + if ! id -u "$app" &>/dev/null; then + ynh_print_err --message="There is no \"$app\" system user" + exit 1 + fi + + # Make sure the app has an install_dir setting + local install_dir=$(ynh_app_setting_get --app=$app --key=install_dir) + if [ -z "$install_dir" ] + then + ynh_print_err --message="$app has no install_dir setting (does it use packaging format >=2?)" + exit 1 + fi + + # Load the app's service name, or default to $app + local service=$(ynh_app_setting_get --app=$app --key=service) + [ -z "$service" ] && service=$app; + + # Export HOME variable + export HOME=$install_dir; + + # Load the Environment variables from the app's service + local env_var=$(systemctl show $service.service -p "Environment" --value) + [ -n "$env_var" ] && export $env_var; + + # Force `php` to its intended version + # We use `eval`+`export` since `alias` is not propagated to subshells, even with `export` + local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) + if [ -n "$phpversion" ] + then + eval "php() { php${phpversion} \"\$@\"; }" + export -f php + fi + + # Source the EnvironmentFiles from the app's service + local env_files=($(systemctl show $service.service -p "EnvironmentFiles" --value)) + if [ ${#env_files[*]} -gt 0 ] + then + # set -/+a enables and disables new variables being automatically exported. Needed when using `source`. + set -a + for file in ${env_files[*]} + do + [[ $file = /* ]] && source $file + done + set +a + fi + + # cd into the WorkingDirectory set in the service, or default to the install_dir + local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value) + [ -z $env_dir ] && env_dir=$install_dir; + cd $env_dir + + # Spawn the app shell + su -s /bin/bash $app +} diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 58787790c..e1de66bc8 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -954,6 +954,12 @@ app: help: Delete the key action: store_true + ### app_shell() + shell: + action_help: Open an interactive shell with the app environment already loaded + arguments: + app: + help: App ID ### app_register_url() register-url: diff --git a/src/app.py b/src/app.py index 2eb201a81..04340b1ba 100644 --- a/src/app.py +++ b/src/app.py @@ -1645,6 +1645,16 @@ def app_setting(app, key, value=None, delete=False): _set_app_settings(app, app_settings) +def app_shell(app): + """ + Open an interactive shell with the app environment already loaded + + Keyword argument: + app -- App ID + + """ + subprocess.run(['/bin/bash', '-c', 'source /usr/share/yunohost/helpers && ynh_spawn_app_shell '+app]) + def app_register_url(app, domain, path): """ Book/register a web path for a given app