mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
341 lines
12 KiB
Bash
341 lines
12 KiB
Bash
#!/bin/bash
|
|
|
|
|
|
# Get a value from heterogeneous file (yaml, json, php, python...)
|
|
#
|
|
# usage: ynh_value_get --file=PATH --key=KEY
|
|
# | arg: -f, --file= - the path to the file
|
|
# | arg: -k, --key= - the key to get
|
|
#
|
|
# This helpers match several var affectation use case in several languages
|
|
# We don't use jq or equivalent to keep comments and blank space in files
|
|
# This helpers work line by line, it is not able to work correctly
|
|
# if you have several identical keys in your files
|
|
#
|
|
# Example of line this helpers can managed correctly
|
|
# .yml
|
|
# title: YunoHost documentation
|
|
# email: 'yunohost@yunohost.org'
|
|
# .json
|
|
# "theme": "colib'ris",
|
|
# "port": 8102
|
|
# "some_boolean": false,
|
|
# "user": null
|
|
# .ini
|
|
# some_boolean = On
|
|
# action = "Clear"
|
|
# port = 20
|
|
# .php
|
|
# $user=
|
|
# user => 20
|
|
# .py
|
|
# USER = 8102
|
|
# user = 'https://donate.local'
|
|
# CUSTOM['user'] = 'YunoHost'
|
|
# Requires YunoHost version 4.3 or higher.
|
|
ynh_value_get() {
|
|
# Declare an array to define the options of this helper.
|
|
local legacy_args=fk
|
|
local -A args_array=( [f]=file= [k]=key= )
|
|
local file
|
|
local key
|
|
# Manage arguments with getopts
|
|
ynh_handle_getopts_args "$@"
|
|
|
|
local var_part='^[ \t]*\$?(\w*\[)?[ \t]*["'"']?${key}['"'"]?[ \t]*\]?[ \t]*[:=]>?[ \t]*'
|
|
|
|
local crazy_value="$((grep -i -o -P '^[ \t]*\$?(\w*\[)?[ \t]*["'"']?${key}['"'"]?[ \t]*\]?[ \t]*[:=]>?[ \t]*\K.*(?=[ \t,\n;]*$)' ${file} || echo YNH_NULL) | head -n1)"
|
|
#"
|
|
|
|
local first_char="${crazy_value:0:1}"
|
|
if [[ "$first_char" == '"' ]] ; then
|
|
echo "$crazy_value" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
|
|
elif [[ "$first_char" == "'" ]] ; then
|
|
echo "$crazy_value" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
|
|
else
|
|
echo "$crazy_value"
|
|
fi
|
|
}
|
|
|
|
# Set a value into heterogeneous file (yaml, json, php, python...)
|
|
#
|
|
# usage: ynh_value_set --file=PATH --key=KEY --value=VALUE
|
|
# | arg: -f, --file= - the path to the file
|
|
# | arg: -k, --key= - the key to set
|
|
# | arg: -v, --value= - the value to set
|
|
#
|
|
# Requires YunoHost version 4.3 or higher.
|
|
ynh_value_set() {
|
|
# Declare an array to define the options of this helper.
|
|
local legacy_args=fkv
|
|
local -A args_array=( [f]=file= [k]=key= [v]=value=)
|
|
local file
|
|
local key
|
|
local value
|
|
# Manage arguments with getopts
|
|
ynh_handle_getopts_args "$@"
|
|
|
|
local var_part='^[ \t]*\$?(\w*\[)?[ \t]*["'"']?${key}['"'"]?[ \t]*\]?[ \t]*[:=]>?[ \t]*'
|
|
|
|
local crazy_value="$(grep -i -o -P "${var_part}\K.*(?=[ \t,\n;]*\$)" ${file} | head -n1)"
|
|
local var_part="^[ \t]*(\$?\w*\[)?[ \t]*[\"']?${key}[\"']?[ \t]*\]?[ \t]*[:=]>?[ \t]*"
|
|
local first_char="${crazy_value:0:1}"
|
|
if [[ "$first_char" == '"' ]] ; then
|
|
value="$(echo "$value" | sed 's/"/\\"/g')"
|
|
sed -ri "s%(${var_part}\")[^\"]*(\"[ \t\n,;]*)\$%\1${value}\2%i" ${file}
|
|
elif [[ "$first_char" == "'" ]] ; then
|
|
value="$(echo "$value" | sed "s/'/\\\\'/g")"
|
|
sed -ri "s%(${var_part}')[^']*('[ \t\n,;]*)\$%\1${value}\2%i" ${file}
|
|
else
|
|
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] ; then
|
|
value="\"$(echo "$value" | sed 's/"/\\"/g')\""
|
|
fi
|
|
sed -ri "s%(${var_part}')[^']*('[ \t\n,;]*)\$%\1${value}\2%i" ${file}
|
|
fi
|
|
}
|
|
|
|
_ynh_panel_get() {
|
|
# From settings
|
|
local lines
|
|
lines=`python3 << EOL
|
|
import toml
|
|
from collections import OrderedDict
|
|
with open("../config_panel.toml", "r") as f:
|
|
file_content = f.read()
|
|
loaded_toml = toml.loads(file_content, _dict=OrderedDict)
|
|
|
|
for panel_name, panel in loaded_toml.items():
|
|
if not isinstance(panel, dict): continue
|
|
for section_name, section in panel.items():
|
|
if not isinstance(section, dict): continue
|
|
for name, param in section.items():
|
|
if not isinstance(param, dict):
|
|
continue
|
|
print(';'.join([
|
|
name,
|
|
param.get('type', 'string'),
|
|
param.get('source', 'settings' if param.get('type', 'string') != 'file' else '')
|
|
]))
|
|
EOL
|
|
`
|
|
for line in $lines
|
|
do
|
|
IFS=';' read short_setting type source <<< "$line"
|
|
local getter="get__${short_setting}"
|
|
sources[${short_setting}]="$source"
|
|
types[${short_setting}]="$type"
|
|
file_hash[${short_setting}]=""
|
|
formats[${short_setting}]=""
|
|
# Get value from getter if exists
|
|
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
|
old[$short_setting]="$($getter)"
|
|
formats[${short_setting}]="yaml"
|
|
|
|
elif [[ "$source" == "" ]] ; then
|
|
old[$short_setting]="YNH_NULL"
|
|
|
|
# Get value from app settings or from another file
|
|
elif [[ "$type" == "file" ]] ; then
|
|
if [[ "$source" == "settings" ]] ; then
|
|
ynh_die "File '${short_setting}' can't be stored in settings"
|
|
fi
|
|
old[$short_setting]="$(ls $(echo $source | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2> /dev/null || echo YNH_NULL)"
|
|
file_hash[$short_setting]="true"
|
|
|
|
# Get multiline text from settings or from a full file
|
|
elif [[ "$type" == "text" ]] ; then
|
|
if [[ "$source" == "settings" ]] ; then
|
|
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
|
|
elif [[ "$source" == *":"* ]] ; then
|
|
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
|
|
else
|
|
old[$short_setting]="$(cat $(echo $source | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/) 2> /dev/null || echo YNH_NULL)"
|
|
fi
|
|
|
|
# Get value from a kind of key/value file
|
|
else
|
|
if [[ "$source" == "settings" ]] ; then
|
|
source=":/etc/yunohost/apps/$app/settings.yml"
|
|
fi
|
|
local source_key="$(echo "$source" | cut -d: -f1)"
|
|
source_key=${source_key:-$short_setting}
|
|
local source_file="$(echo "$source" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
old[$short_setting]="$(ynh_value_get --file="${source_file}" --key="${source_key}")"
|
|
|
|
fi
|
|
done
|
|
|
|
|
|
}
|
|
|
|
_ynh_panel_apply() {
|
|
for short_setting in "${!old[@]}"
|
|
do
|
|
local setter="set__${short_setting}"
|
|
local source="${sources[$short_setting]}"
|
|
local type="${types[$short_setting]}"
|
|
if [ "${changed[$short_setting]}" == "true" ] ; then
|
|
# Apply setter if exists
|
|
if type -t $setter 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
|
$setter
|
|
|
|
elif [[ "$source" == "" ]] ; then
|
|
continue
|
|
|
|
# Save in a file
|
|
elif [[ "$type" == "file" ]] ; then
|
|
if [[ "$source" == "settings" ]] ; then
|
|
ynh_die "File '${short_setting}' can't be stored in settings"
|
|
fi
|
|
local source_file="$(echo "$source" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
cp "${!short_setting}" "$source_file"
|
|
|
|
# Save value in app settings
|
|
elif [[ "$source" == "settings" ]] ; then
|
|
ynh_app_setting_set $app $short_setting "${!short_setting}"
|
|
|
|
# Save multiline text in a file
|
|
elif [[ "$type" == "text" ]] ; then
|
|
if [[ "$source" == *":"* ]] ; then
|
|
ynh_die "For technical reasons, multiline text '${short_setting}' can't be stored automatically in a variable file, you have to create custom getter/setter"
|
|
fi
|
|
local source_file="$(echo "$source" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
echo "${!short_setting}" > "$source_file"
|
|
|
|
# Set value into a kind of key/value file
|
|
else
|
|
local source_key="$(echo "$source" | cut -d: -f1)"
|
|
source_key=${source_key:-$short_setting}
|
|
local source_file="$(echo "$source" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
ynh_value_set --file="${source_file}" --key="${source_key}" --value="${!short_setting}"
|
|
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
_ynh_panel_show() {
|
|
for short_setting in "${!old[@]}"
|
|
do
|
|
if [[ "${old[$short_setting]}" != YNH_NULL ]] ; then
|
|
if [[ "${formats[$short_setting]}" == "yaml" ]] ; then
|
|
ynh_return "${short_setting}:"
|
|
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
|
else
|
|
ynh_return "${short_setting}: \"$(echo "${old[$short_setting]}" | sed ':a;N;$!ba;s/\n/\n\n/g')\""
|
|
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
_ynh_panel_validate() {
|
|
# Change detection
|
|
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
|
|
local is_error=true
|
|
#for changed_status in "${!changed[@]}"
|
|
for short_setting in "${!old[@]}"
|
|
do
|
|
changed[$short_setting]=false
|
|
if [ -z ${!short_setting+x} ]; then
|
|
# Assign the var with the old value in order to allows multiple
|
|
# args validation
|
|
declare "$short_setting"="${old[$short_setting]}"
|
|
continue
|
|
fi
|
|
if [ ! -z "${file_hash[${short_setting}]}" ] ; then
|
|
file_hash[old__$short_setting]=""
|
|
file_hash[new__$short_setting]=""
|
|
if [ -f "${old[$short_setting]}" ] ; then
|
|
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
|
|
fi
|
|
if [ -f "${!short_setting}" ] ; then
|
|
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
|
|
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]
|
|
then
|
|
changed[$short_setting]=true
|
|
is_error=false
|
|
fi
|
|
fi
|
|
else
|
|
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]
|
|
then
|
|
changed[$short_setting]=true
|
|
is_error=false
|
|
fi
|
|
fi
|
|
done
|
|
if [[ "$is_error" == "true" ]]
|
|
then
|
|
ynh_print_info "Nothing has changed"
|
|
exit 0
|
|
fi
|
|
|
|
# Run validation if something is changed
|
|
ynh_script_progression --message="Validating the new configuration..." --weight=1
|
|
|
|
for short_setting in "${!old[@]}"
|
|
do
|
|
[[ "${changed[$short_setting]}" == "false" ]] && continue
|
|
local result=""
|
|
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
|
|
result="$(validate__$short_setting)"
|
|
fi
|
|
if [ -n "$result" ]
|
|
then
|
|
local key="YNH_ERROR_${short_setting}"
|
|
ynh_return "$key: \"$result\""
|
|
is_error=true
|
|
fi
|
|
done
|
|
|
|
if [[ "$is_error" == "true" ]]
|
|
then
|
|
exit 0
|
|
fi
|
|
|
|
}
|
|
|
|
ynh_panel_get() {
|
|
_ynh_panel_get
|
|
}
|
|
|
|
ynh_panel_show() {
|
|
_ynh_panel_show
|
|
}
|
|
|
|
ynh_panel_validate() {
|
|
_ynh_panel_validate
|
|
}
|
|
|
|
ynh_panel_apply() {
|
|
_ynh_panel_apply
|
|
}
|
|
|
|
ynh_panel_run() {
|
|
declare -Ag old=()
|
|
declare -Ag changed=()
|
|
declare -Ag file_hash=()
|
|
declare -Ag sources=()
|
|
declare -Ag types=()
|
|
declare -Ag formats=()
|
|
|
|
case $1 in
|
|
show)
|
|
ynh_panel_get
|
|
ynh_panel_show
|
|
;;
|
|
apply)
|
|
max_progression=4
|
|
ynh_script_progression --message="Reading config panel description and current configuration..."
|
|
ynh_panel_get
|
|
|
|
ynh_panel_validate
|
|
|
|
ynh_script_progression --message="Applying the new configuration..."
|
|
ynh_panel_apply
|
|
ynh_script_progression --message="Configuration of $app completed" --last
|
|
;;
|
|
esac
|
|
}
|
|
|