From 3bb32dc1e4a166e7c80520338c6c1fc484046924 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 3 May 2023 19:59:28 +0000 Subject: [PATCH 01/17] Init app_shell --- share/actionsmap.yml | 6 ++++++ src/app.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) 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..0db33a373 100644 --- a/src/app.py +++ b/src/app.py @@ -1645,6 +1645,26 @@ 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 + + """ + app_settings = _get_app_settings(app) or {} + + #TODO init a env_dict + #TODO load the app's environment, parsed from: + #TODO - its settings (phpversion, ...) + #TODO - its service configuration (PATH, NodeJS production mode...) + #TODO this one could be performed in Bash, directly after initiating the subprocess: + #TODO - "Environment" clause: `systemctl show $app.service -p "Environment" --value` + #TODO - Source "EnvironmentFile" clauses + #TODO + #TODO find out how to open an interactive Bash shell from Python + def app_register_url(app, domain, path): """ Book/register a web path for a given app From d27e9a9eea9907f0482e2bfee6fe13bbdda02654 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 9 May 2023 21:29:52 +0000 Subject: [PATCH 02/17] Add ynh_load_app_environment helper --- helpers/apps | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/app.py | 11 ++-------- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/helpers/apps b/helpers/apps index 85b74de15..c5fe6cdad 100644 --- a/helpers/apps +++ b/helpers/apps @@ -111,3 +111,61 @@ ynh_remove_apps() { done fi } + +# Load an app environment in the current Bash shell +# +# usage: ynh_install_apps --app="app" +# | arg: -a, --app= - the app ID +# +# Requires YunoHost version 11.0.* or higher. +ynh_load_app_environment() { + # 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 "$@" + + # Retrieve the list of installed apps + local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id)) + + # 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 + 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 an install_dir setting + install_dir="$(yunohost app setting $app 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 Environment variables from the app's service + env_var=`systemctl show $app.service -p "Environment" --value` + [ -n "$env_var" ] && export $env_var; + export HOME=$install_dir; + + # Source the EnvironmentFiles from the app's service + env_files=(`systemctl show $app.service -p "EnvironmentFiles" --value`) + if [ ${#env_files[*]} -gt 0 ] + then + for file in ${env_files[*]} + do + [[ $file = /* ]] && source $file + done + fi + + # Open the app shell + su -s /bin/bash $app +} diff --git a/src/app.py b/src/app.py index 0db33a373..2b602f351 100644 --- a/src/app.py +++ b/src/app.py @@ -1655,15 +1655,8 @@ def app_shell(app): """ app_settings = _get_app_settings(app) or {} - #TODO init a env_dict - #TODO load the app's environment, parsed from: - #TODO - its settings (phpversion, ...) - #TODO - its service configuration (PATH, NodeJS production mode...) - #TODO this one could be performed in Bash, directly after initiating the subprocess: - #TODO - "Environment" clause: `systemctl show $app.service -p "Environment" --value` - #TODO - Source "EnvironmentFile" clauses - #TODO - #TODO find out how to open an interactive Bash shell from Python + #TODO Find out how to open an interactive Bash shell from Python + #TODO run `ynh_load_app_environment --app=$app` helper in there def app_register_url(app, domain, path): """ From 68a4f2b4bc6f36caca5203f6bd80d4400c5ae571 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 18 May 2023 16:10:21 +0000 Subject: [PATCH 03/17] Improve ynh_load_environment helper --- helpers/apps | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/helpers/apps b/helpers/apps index c5fe6cdad..bb60fea59 100644 --- a/helpers/apps +++ b/helpers/apps @@ -126,9 +126,6 @@ ynh_load_app_environment() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - # Retrieve the list of installed apps - local installed_apps_list=($(yunohost app list --output-as json --quiet | jq -r .apps[].id)) - # Force Bash to be used to run this helper if [ $0 != "bash" ] then @@ -137,14 +134,21 @@ ynh_load_app_environment() { 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 is installed + 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 - install_dir="$(yunohost app setting $app install_dir)" + local install_dir="$(yunohost app setting $app install_dir)" if [ -z "$install_dir" ] then ynh_print_err --message="$app has no install_dir setting (does it use packaging format >=2?)" @@ -152,18 +156,21 @@ ynh_load_app_environment() { fi # Load the Environment variables from the app's service - env_var=`systemctl show $app.service -p "Environment" --value` + local env_var=`systemctl show $app.service -p "Environment" --value` [ -n "$env_var" ] && export $env_var; export HOME=$install_dir; # Source the EnvironmentFiles from the app's service - env_files=(`systemctl show $app.service -p "EnvironmentFiles" --value`) + local env_files=(`systemctl show $app.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 # Open the app shell From 425670bcfb380135d3df96007eb43b4cf624bfb6 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 18 May 2023 16:14:30 +0000 Subject: [PATCH 04/17] Remove useless var declaration in app_shell function --- src/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app.py b/src/app.py index 2b602f351..a9bfad1a9 100644 --- a/src/app.py +++ b/src/app.py @@ -1653,7 +1653,6 @@ def app_shell(app): app -- App ID """ - app_settings = _get_app_settings(app) or {} #TODO Find out how to open an interactive Bash shell from Python #TODO run `ynh_load_app_environment --app=$app` helper in there From 072dabaf7099082f9280c87a9345065725f468c9 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 18 May 2023 16:45:17 +0000 Subject: [PATCH 05/17] Fix Bash detection for ynh_load_app_environment --- helpers/apps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/apps b/helpers/apps index bb60fea59..b9cc03b58 100644 --- a/helpers/apps +++ b/helpers/apps @@ -127,7 +127,7 @@ ynh_load_app_environment() { ynh_handle_getopts_args "$@" # Force Bash to be used to run this helper - if [ $0 != "bash" ] + if [[ ! $0 =~ \/?bash$ ]] then ynh_print_err --message="Please use Bash as shell" exit 1 From 2b65913b8966d17318d6e2403575b170fee4ed09 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 18 May 2023 19:35:56 +0000 Subject: [PATCH 06/17] Launch app shell --- src/app.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app.py b/src/app.py index a9bfad1a9..6b523d574 100644 --- a/src/app.py +++ b/src/app.py @@ -1653,9 +1653,7 @@ def app_shell(app): app -- App ID """ - - #TODO Find out how to open an interactive Bash shell from Python - #TODO run `ynh_load_app_environment --app=$app` helper in there + subprocess.run(['/bin/bash', '-c', 'source /usr/share/yunohost/helpers && ynh_load_app_environment '+app]) def app_register_url(app, domain, path): """ From 21c7c41812535da1597b492239790118da2d8ce9 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 23:08:53 +0200 Subject: [PATCH 07/17] Extend ynh_load_app_environment usage examples Co-authored-by: Florent --- helpers/apps | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/helpers/apps b/helpers/apps index b9cc03b58..d807a4d87 100644 --- a/helpers/apps +++ b/helpers/apps @@ -117,6 +117,10 @@ ynh_remove_apps() { # usage: ynh_install_apps --app="app" # | arg: -a, --app= - the app ID # +# examples: +# ynh_load_app_environment --app="APP" <<< 'echo "$USER"' +# ynh_load_app_environment --app="APP" < /tmp/some_script.bash +# # Requires YunoHost version 11.0.* or higher. ynh_load_app_environment() { # Declare an array to define the options of this helper. From cc167cd92c60b70c75c89da7e18d35b767aafa1e Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 21:11:32 +0000 Subject: [PATCH 08/17] Rename ynh_load_app_environment into ynh_spawn_app_shell Co-authored-by: Florent --- helpers/apps | 8 ++++---- src/app.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/helpers/apps b/helpers/apps index d807a4d87..fb5ac25b0 100644 --- a/helpers/apps +++ b/helpers/apps @@ -118,11 +118,11 @@ ynh_remove_apps() { # | arg: -a, --app= - the app ID # # examples: -# ynh_load_app_environment --app="APP" <<< 'echo "$USER"' -# ynh_load_app_environment --app="APP" < /tmp/some_script.bash -# +# 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. -ynh_load_app_environment() { +ynh_spawn_app_shell() { # Declare an array to define the options of this helper. local legacy_args=a local -A args_array=([a]=app=) diff --git a/src/app.py b/src/app.py index 6b523d574..04340b1ba 100644 --- a/src/app.py +++ b/src/app.py @@ -1653,7 +1653,7 @@ def app_shell(app): app -- App ID """ - subprocess.run(['/bin/bash', '-c', 'source /usr/share/yunohost/helpers && ynh_load_app_environment '+app]) + subprocess.run(['/bin/bash', '-c', 'source /usr/share/yunohost/helpers && ynh_spawn_app_shell '+app]) def app_register_url(app, domain, path): """ From 4b4ce9aef63ba4408fdc87d0e13a6a3b1a3d9220 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 23:13:52 +0200 Subject: [PATCH 09/17] Default to WorkingDirectory then install_dir for ynh_spawn_app_shell Co-authored-by: Tagada <36127788+Tagadda@users.noreply.github.com> --- helpers/apps | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helpers/apps b/helpers/apps index fb5ac25b0..feda02f5e 100644 --- a/helpers/apps +++ b/helpers/apps @@ -178,5 +178,12 @@ ynh_spawn_app_shell() { fi # Open the app shell + local env_dir = $(systemctl show $app.service -p "WorkingDirectory" --value) + if [[ $env_dir = "" ]]; + then + env_dir = $install_dir + fi + + cd $env_dir su -s /bin/bash $app } From ed1b5e567bc18f27031676cf62e98ec83d9a6d8e Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 21:55:20 +0000 Subject: [PATCH 10/17] Force php to its intended version in ynh_spawn_app_shell --- helpers/apps | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/helpers/apps b/helpers/apps index feda02f5e..23889ef43 100644 --- a/helpers/apps +++ b/helpers/apps @@ -164,6 +164,14 @@ ynh_spawn_app_shell() { [ -n "$env_var" ] && export $env_var; export HOME=$install_dir; + # Force `php` to its intended version + 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 $app.service -p "EnvironmentFiles" --value`) if [ ${#env_files[*]} -gt 0 ] From a47e491869673574ac8233a179bd75622c29d5ee Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 22:08:51 +0000 Subject: [PATCH 11/17] Cleanup ynh_spawn_app_shell --- helpers/apps | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/helpers/apps b/helpers/apps index 23889ef43..1f3fb5430 100644 --- a/helpers/apps +++ b/helpers/apps @@ -152,7 +152,7 @@ ynh_spawn_app_shell() { fi # Make sure the app has an install_dir setting - local install_dir="$(yunohost app setting $app install_dir)" + 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?)" @@ -185,13 +185,11 @@ ynh_spawn_app_shell() { set +a fi - # Open the app shell + # cd into the WorkingDirectory set in the service, or default to the install_dir local env_dir = $(systemctl show $app.service -p "WorkingDirectory" --value) - if [[ $env_dir = "" ]]; - then - env_dir = $install_dir - fi - + [ -z $env_dir ] && env_dir=$install_dir; cd $env_dir + + # Spawn the app shell su -s /bin/bash $app } From 5fa58f19ce264f52e9d3a6d18f8cbd7ce0b2e358 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 22:19:10 +0000 Subject: [PATCH 12/17] Offer apps to set service name for ynh_spawn_app_shell --- helpers/apps | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/helpers/apps b/helpers/apps index 1f3fb5430..aafcfa7e2 100644 --- a/helpers/apps +++ b/helpers/apps @@ -159,8 +159,12 @@ ynh_spawn_app_shell() { 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; + # Load the Environment variables from the app's service - local env_var=`systemctl show $app.service -p "Environment" --value` + local env_var=`systemctl show $service.service -p "Environment" --value` [ -n "$env_var" ] && export $env_var; export HOME=$install_dir; @@ -173,7 +177,7 @@ ynh_spawn_app_shell() { fi # Source the EnvironmentFiles from the app's service - local env_files=(`systemctl show $app.service -p "EnvironmentFiles" --value`) + 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`. @@ -186,7 +190,7 @@ ynh_spawn_app_shell() { fi # cd into the WorkingDirectory set in the service, or default to the install_dir - local env_dir = $(systemctl show $app.service -p "WorkingDirectory" --value) + local env_dir = $(systemctl show $service.service -p "WorkingDirectory" --value) [ -z $env_dir ] && env_dir=$install_dir; cd $env_dir From cacd43e147e444ede67c3c1754d45fadd56ade54 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 22:21:35 +0000 Subject: [PATCH 13/17] Fix error in ynh_spawn_app_shell --- helpers/apps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/apps b/helpers/apps index aafcfa7e2..198aa15d9 100644 --- a/helpers/apps +++ b/helpers/apps @@ -190,7 +190,7 @@ ynh_spawn_app_shell() { 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) + local env_dir=$(systemctl show $service.service -p "WorkingDirectory" --value) [ -z $env_dir ] && env_dir=$install_dir; cd $env_dir From bb9db08e2902c8734ae547a43f02fec0445783ce Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 24 May 2023 22:32:51 +0000 Subject: [PATCH 14/17] Improve ynh_spawn_app_shell documentation --- helpers/apps | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/helpers/apps b/helpers/apps index 198aa15d9..9c46346fe 100644 --- a/helpers/apps +++ b/helpers/apps @@ -112,16 +112,19 @@ ynh_remove_apps() { fi } -# Load an app environment in the current Bash shell +# Spawn a Bash shell with the app environment loaded # -# usage: ynh_install_apps --app="app" +# 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. +# 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 From 1300585eda965691a078db909a289b9dfef26828 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 25 May 2023 09:48:55 +0200 Subject: [PATCH 15/17] Improve ynh_spawn_app_shell comments Co-authored-by: Florent --- helpers/apps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/apps b/helpers/apps index 9c46346fe..b81e8be99 100644 --- a/helpers/apps +++ b/helpers/apps @@ -148,7 +148,7 @@ ynh_spawn_app_shell() { exit 1 fi - # Make sure the app is installed + # 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 From db7ab2a98b276c23dbc2cf67c6e92e116536f36f Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 30 May 2023 11:18:54 +0000 Subject: [PATCH 16/17] Homogeneize command subtitutions in ynh_spawn_app_shell --- helpers/apps | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers/apps b/helpers/apps index b81e8be99..4b64ecdbb 100644 --- a/helpers/apps +++ b/helpers/apps @@ -167,7 +167,7 @@ ynh_spawn_app_shell() { [ -z "$service" ] && service=$app; # Load the Environment variables from the app's service - local env_var=`systemctl show $service.service -p "Environment" --value` + local env_var=$(systemctl show $service.service -p "Environment" --value) [ -n "$env_var" ] && export $env_var; export HOME=$install_dir; @@ -180,7 +180,7 @@ ynh_spawn_app_shell() { fi # Source the EnvironmentFiles from the app's service - local env_files=(`systemctl show $service.service -p "EnvironmentFiles" --value`) + 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`. From f3faac87f83dd9deebed02b7700ed3f23308f7c7 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 30 May 2023 11:27:33 +0000 Subject: [PATCH 17/17] Improve comments of ynh_spawn_app_shell --- helpers/apps | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helpers/apps b/helpers/apps index 4b64ecdbb..4b253ff90 100644 --- a/helpers/apps +++ b/helpers/apps @@ -166,12 +166,15 @@ ynh_spawn_app_shell() { 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; - export HOME=$install_dir; # 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