mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'dev' into migrate_to_bullseye
This commit is contained in:
commit
480875f676
88 changed files with 4482 additions and 3697 deletions
2
.coveragerc
Normal file
2
.coveragerc
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[report]
|
||||||
|
omit=src/yunohost/tests/*,src/yunohost/vendor/*,/usr/lib/moulinette/yunohost/*
|
|
@ -36,7 +36,7 @@ full-tests:
|
||||||
- *install_debs
|
- *install_debs
|
||||||
- yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace
|
- yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns --force-diskspace
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest --cov=yunohost tests/ src/yunohost/tests/ --junitxml=report.xml
|
- python3 -m pytest --cov=yunohost tests/ src/yunohost/tests/ data/hooks/diagnosis/ --junitxml=report.xml
|
||||||
- cd tests
|
- cd tests
|
||||||
- bash test_helpers.sh
|
- bash test_helpers.sh
|
||||||
needs:
|
needs:
|
||||||
|
@ -113,10 +113,10 @@ test-apps:
|
||||||
test-appscatalog:
|
test-appscatalog:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
script:
|
script:
|
||||||
- python3 -m pytest src/yunohost/tests/test_appscatalog.py
|
- python3 -m pytest src/yunohost/tests/test_app_catalog.py
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
- src/yunohost/app.py
|
- src/yunohost/app_calalog.py
|
||||||
|
|
||||||
test-appurl:
|
test-appurl:
|
||||||
extends: .test-stage
|
extends: .test-stage
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
|

|
||||||
[](https://gitlab.com/yunohost/yunohost/-/pipelines)
|
[](https://gitlab.com/yunohost/yunohost/-/pipelines)
|
||||||
|

|
||||||
[](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
|
[](https://github.com/YunoHost/yunohost/blob/dev/LICENSE)
|
||||||
[](https://mastodon.social/@yunohost)
|
[](https://mastodon.social/@yunohost)
|
||||||
|
|
||||||
|
|
235
bin/yunomdns
235
bin/yunomdns
|
@ -4,160 +4,152 @@
|
||||||
Pythonic declaration of mDNS .local domains for YunoHost
|
Pythonic declaration of mDNS .local domains for YunoHost
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
import socket
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
|
|
||||||
from zeroconf import Zeroconf, ServiceInfo
|
import ifaddr
|
||||||
|
from ipaddress import ip_address
|
||||||
|
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
|
||||||
|
|
||||||
# Helper command taken from Moulinette
|
|
||||||
def check_output(args, stderr=subprocess.STDOUT, shell=True, **kwargs):
|
def get_network_local_interfaces() -> Dict[str, Dict[str, List[str]]]:
|
||||||
"""Run command with arguments and return its output as a byte string
|
|
||||||
Overwrite some of the arguments to capture standard error in the result
|
|
||||||
and use shell by default before calling subprocess.check_output.
|
|
||||||
"""
|
"""
|
||||||
return (
|
Returns interfaces with their associated local IPs
|
||||||
subprocess.check_output(args, stderr=stderr, shell=shell, **kwargs)
|
|
||||||
.decode("utf-8")
|
|
||||||
.strip()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Helper command taken from Moulinette
|
|
||||||
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
|
|
||||||
"""
|
"""
|
||||||
Extract IP addresses (v4 and/or v6) from a string limited to one
|
|
||||||
address by protocol
|
|
||||||
|
|
||||||
Keyword argument:
|
interfaces = {
|
||||||
string -- String to search in
|
adapter.name: {
|
||||||
skip_netmask -- True to skip subnet mask extraction
|
"ipv4": [ip.ip for ip in adapter.ips if ip.is_IPv4 and ip_address(ip.ip).is_private],
|
||||||
skip_loopback -- False to include addresses reserved for the
|
"ipv6": [ip.ip[0] for ip in adapter.ips if ip.is_IPv6 and ip_address(ip.ip[0]).is_private and not ip_address(ip.ip[0]).is_link_local],
|
||||||
loopback interface
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A dict of {protocol: address} with protocol one of 'ipv4' or 'ipv6'
|
|
||||||
|
|
||||||
"""
|
|
||||||
ip4_pattern = (
|
|
||||||
r"((25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}"
|
|
||||||
)
|
|
||||||
ip6_pattern = r"(((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::?((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)"
|
|
||||||
ip4_pattern += r"/[0-9]{1,2})" if not skip_netmask else ")"
|
|
||||||
ip6_pattern += r"/[0-9]{1,3})" if not skip_netmask else ")"
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
for m in re.finditer(ip4_pattern, string):
|
|
||||||
addr = m.group(1)
|
|
||||||
if skip_loopback and addr.startswith("127."):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Limit to only one result
|
|
||||||
result["ipv4"] = addr
|
|
||||||
break
|
|
||||||
|
|
||||||
for m in re.finditer(ip6_pattern, string):
|
|
||||||
addr = m.group(1)
|
|
||||||
if skip_loopback and addr == "::1":
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Limit to only one result
|
|
||||||
result["ipv6"] = addr
|
|
||||||
break
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Helper command taken from Moulinette
|
|
||||||
def get_network_interfaces():
|
|
||||||
|
|
||||||
# Get network devices and their addresses (raw infos from 'ip addr')
|
|
||||||
devices_raw = {}
|
|
||||||
output = check_output("ip --brief a").split("\n")
|
|
||||||
for line in output:
|
|
||||||
line = line.split()
|
|
||||||
iname = line[0]
|
|
||||||
ips = ' '.join(line[2:])
|
|
||||||
|
|
||||||
devices_raw[iname] = ips
|
|
||||||
|
|
||||||
# Parse relevant informations for each of them
|
|
||||||
devices = {
|
|
||||||
name: _extract_inet(addrs)
|
|
||||||
for name, addrs in devices_raw.items()
|
|
||||||
if name != "lo"
|
|
||||||
}
|
}
|
||||||
|
for adapter in ifaddr.get_adapters()
|
||||||
|
if adapter.name != "lo"
|
||||||
|
}
|
||||||
|
return interfaces
|
||||||
|
|
||||||
return devices
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
# Listener class, to detect duplicates on the network
|
||||||
|
# Stores the list of servers in its list property
|
||||||
|
class Listener:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.list = []
|
||||||
|
|
||||||
|
def remove_service(self, zeroconf, type, name):
|
||||||
|
info = zeroconf.get_service_info(type, name)
|
||||||
|
self.list.remove(info.server)
|
||||||
|
|
||||||
|
def update_service(self, zeroconf, type, name):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_service(self, zeroconf, type, name):
|
||||||
|
info = zeroconf.get_service_info(type, name)
|
||||||
|
self.list.append(info.server[:-1])
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> bool:
|
||||||
###
|
###
|
||||||
# CONFIG
|
# CONFIG
|
||||||
###
|
###
|
||||||
|
|
||||||
with open('/etc/yunohost/mdns.yml', 'r') as f:
|
with open("/etc/yunohost/mdns.yml", "r") as f:
|
||||||
config = yaml.safe_load(f) or {}
|
config = yaml.safe_load(f) or {}
|
||||||
updated = False
|
|
||||||
|
|
||||||
required_fields = ["interfaces", "domains"]
|
required_fields = ["domains"]
|
||||||
missing_fields = [field for field in required_fields if field not in config]
|
missing_fields = [field for field in required_fields if field not in config]
|
||||||
|
interfaces = get_network_local_interfaces()
|
||||||
|
|
||||||
if missing_fields:
|
if missing_fields:
|
||||||
print("The fields %s are required" % ', '.join(missing_fields))
|
print(f"The fields {missing_fields} are required in mdns.yml")
|
||||||
|
return False
|
||||||
|
|
||||||
if config['interfaces'] is None:
|
if "interfaces" not in config:
|
||||||
print('No interface listed for broadcast.')
|
config["interfaces"] = [interface
|
||||||
sys.exit(0)
|
for interface, local_ips in interfaces.items()
|
||||||
|
if local_ips["ipv4"]]
|
||||||
|
|
||||||
if 'yunohost.local' not in config['domains']:
|
if "ban_interfaces" in config:
|
||||||
config['domains'].append('yunohost.local')
|
config["interfaces"] = [interface
|
||||||
|
for interface in config["interfaces"]
|
||||||
|
if interface not in config["ban_interfaces"]]
|
||||||
|
|
||||||
zcs = {}
|
# Let's discover currently published .local domains accross the network
|
||||||
interfaces = get_network_interfaces()
|
zc = Zeroconf()
|
||||||
for interface in config['interfaces']:
|
listener = Listener()
|
||||||
infos = [] # List of ServiceInfo objects, to feed Zeroconf
|
browser = ServiceBrowser(zc, "_device-info._tcp.local.", listener)
|
||||||
ips = [] # Human-readable IPs
|
sleep(2)
|
||||||
b_ips = [] # Binary-convered IPs
|
browser.cancel()
|
||||||
|
zc.close()
|
||||||
|
|
||||||
ipv4 = interfaces[interface]['ipv4'].split('/')[0]
|
# Always attempt to publish yunohost.local
|
||||||
if ipv4:
|
if "yunohost.local" not in config["domains"]:
|
||||||
ips.append(ipv4)
|
config["domains"].append("yunohost.local")
|
||||||
b_ips.append(socket.inet_pton(socket.AF_INET, ipv4))
|
|
||||||
|
|
||||||
ipv6 = interfaces[interface]['ipv6'].split('/')[0]
|
def find_domain_not_already_published(domain):
|
||||||
if ipv6:
|
|
||||||
ips.append(ipv6)
|
# Try domain.local ... but if it's already published by another entity,
|
||||||
b_ips.append(socket.inet_pton(socket.AF_INET6, ipv6))
|
# try domain-2.local, domain-3.local, ...
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
domain_i = domain
|
||||||
|
|
||||||
|
while domain_i in listener.list:
|
||||||
|
print(f"Uh oh, {domain_i} already exists on the network...")
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
domain_i = domain.replace(".local", f"-{i}.local")
|
||||||
|
|
||||||
|
return domain_i
|
||||||
|
|
||||||
|
config['domains'] = [find_domain_not_already_published(domain) for domain in config['domains']]
|
||||||
|
|
||||||
|
zcs: Dict[Zeroconf, List[ServiceInfo]] = {}
|
||||||
|
|
||||||
|
for interface in config["interfaces"]:
|
||||||
|
|
||||||
|
if interface not in interfaces:
|
||||||
|
print(f"Interface {interface} listed in config file is not present on system.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Only broadcast IPv4 because IPv6 is buggy ... because we ain't using python3-ifaddr >= 0.1.7
|
||||||
|
# Buster only ships 0.1.6
|
||||||
|
# Bullseye ships 0.1.7
|
||||||
|
# To be re-enabled once we're on bullseye...
|
||||||
|
# ips: List[str] = interfaces[interface]["ipv4"] + interfaces[interface]["ipv6"]
|
||||||
|
ips: List[str] = interfaces[interface]["ipv4"]
|
||||||
|
|
||||||
# If at least one IP is listed
|
# If at least one IP is listed
|
||||||
if ips:
|
if not ips:
|
||||||
|
continue
|
||||||
|
|
||||||
# Create a Zeroconf object, and store the ServiceInfos
|
# Create a Zeroconf object, and store the ServiceInfos
|
||||||
zc = Zeroconf(interfaces=ips)
|
zc = Zeroconf(interfaces=ips) # type: ignore
|
||||||
zcs[zc]=[]
|
zcs[zc] = []
|
||||||
for d in config['domains']:
|
|
||||||
d_domain=d.replace('.local','')
|
for d in config["domains"]:
|
||||||
if '.' in d_domain:
|
d_domain = d.replace(".local", "")
|
||||||
print(d_domain+'.local: subdomains are not supported.')
|
if "." in d_domain:
|
||||||
else:
|
print(f"{d_domain}.local: subdomains are not supported.")
|
||||||
|
continue
|
||||||
# Create a ServiceInfo object for each .local domain
|
# Create a ServiceInfo object for each .local domain
|
||||||
zcs[zc].append(ServiceInfo(
|
zcs[zc].append(
|
||||||
type_='_device-info._tcp.local.',
|
ServiceInfo(
|
||||||
name=interface+': '+d_domain+'._device-info._tcp.local.',
|
type_="_device-info._tcp.local.",
|
||||||
addresses=b_ips,
|
name=f"{interface}: {d_domain}._device-info._tcp.local.",
|
||||||
|
parsed_addresses=ips,
|
||||||
port=80,
|
port=80,
|
||||||
server=d+'.',
|
server=f"{d}.",
|
||||||
))
|
)
|
||||||
print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface)
|
)
|
||||||
|
print(f"Adding {d} with addresses {ips} on interface {interface}")
|
||||||
|
|
||||||
# Run registration
|
# Run registration
|
||||||
print("Registering...")
|
print("Registering...")
|
||||||
for zc, infos in zcs.items():
|
for zc, infos in zcs.items():
|
||||||
for info in infos:
|
for info in infos:
|
||||||
zc.register_service(info)
|
zc.register_service(info, allow_name_change=True, cooperating_responders=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print("Registered. Press Ctrl+C or stop service to stop.")
|
print("Registered. Press Ctrl+C or stop service to stop.")
|
||||||
|
@ -168,6 +160,11 @@ if __name__ == '__main__':
|
||||||
finally:
|
finally:
|
||||||
print("Unregistering...")
|
print("Unregistering...")
|
||||||
for zc, infos in zcs.items():
|
for zc, infos in zcs.items():
|
||||||
for info in infos:
|
zc.unregister_all_services()
|
||||||
zc.unregister_service(info)
|
|
||||||
zc.close()
|
zc.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(0 if main() else 1)
|
||||||
|
|
|
@ -12,31 +12,27 @@ ynh_wait_dpkg_free() {
|
||||||
local try
|
local try
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
# With seq 1 17, timeout will be almost 30 minutes
|
# With seq 1 17, timeout will be almost 30 minutes
|
||||||
for try in `seq 1 17`
|
for try in $(seq 1 17); do
|
||||||
do
|
|
||||||
# Check if /var/lib/dpkg/lock is used by another process
|
# Check if /var/lib/dpkg/lock is used by another process
|
||||||
if lsof /var/lib/dpkg/lock > /dev/null
|
if lsof /var/lib/dpkg/lock >/dev/null; then
|
||||||
then
|
|
||||||
echo "apt is already in use..."
|
echo "apt is already in use..."
|
||||||
# Sleep an exponential time at each round
|
# Sleep an exponential time at each round
|
||||||
sleep $(( try * try ))
|
sleep $((try * try))
|
||||||
else
|
else
|
||||||
# Check if dpkg hasn't been interrupted and is fully available.
|
# Check if dpkg hasn't been interrupted and is fully available.
|
||||||
# See this for more information: https://sources.debian.org/src/apt/1.4.9/apt-pkg/deb/debsystem.cc/#L141-L174
|
# See this for more information: https://sources.debian.org/src/apt/1.4.9/apt-pkg/deb/debsystem.cc/#L141-L174
|
||||||
local dpkg_dir="/var/lib/dpkg/updates/"
|
local dpkg_dir="/var/lib/dpkg/updates/"
|
||||||
|
|
||||||
# For each file in $dpkg_dir
|
# For each file in $dpkg_dir
|
||||||
while read dpkg_file <&9
|
while read dpkg_file <&9; do
|
||||||
do
|
|
||||||
# Check if the name of this file contains only numbers.
|
# Check if the name of this file contains only numbers.
|
||||||
if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$"
|
if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$"; then
|
||||||
then
|
|
||||||
# If so, that a remaining of dpkg.
|
# If so, that a remaining of dpkg.
|
||||||
ynh_print_err "dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
|
ynh_print_err "dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem."
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
done 9<<< "$(ls -1 $dpkg_dir)"
|
done 9<<<"$(ls -1 $dpkg_dir)"
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
@ -57,7 +53,7 @@ ynh_wait_dpkg_free() {
|
||||||
ynh_package_is_installed() {
|
ynh_package_is_installed() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=package= )
|
local -A args_array=([p]=package=)
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -79,13 +75,12 @@ ynh_package_is_installed() {
|
||||||
ynh_package_version() {
|
ynh_package_version() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=package= )
|
local -A args_array=([p]=package=)
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_package_is_installed "$package"
|
if ynh_package_is_installed "$package"; then
|
||||||
then
|
|
||||||
dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null
|
dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null
|
||||||
else
|
else
|
||||||
echo ''
|
echo ''
|
||||||
|
@ -166,7 +161,7 @@ ynh_package_autopurge() {
|
||||||
# | arg: controlfile - path of the equivs control file
|
# | arg: controlfile - path of the equivs control file
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_install_from_equivs () {
|
ynh_package_install_from_equivs() {
|
||||||
local controlfile=$1
|
local controlfile=$1
|
||||||
|
|
||||||
# retrieve package information
|
# retrieve package information
|
||||||
|
@ -182,7 +177,7 @@ ynh_package_install_from_equivs () {
|
||||||
local TMPDIR=$(mktemp --directory)
|
local TMPDIR=$(mktemp --directory)
|
||||||
|
|
||||||
# Force the compatibility level at 10, levels below are deprecated
|
# Force the compatibility level at 10, levels below are deprecated
|
||||||
echo 10 > /usr/share/equivs/template/debian/compat
|
echo 10 >/usr/share/equivs/template/debian/compat
|
||||||
|
|
||||||
# Note that the cd executes into a sub shell
|
# Note that the cd executes into a sub shell
|
||||||
# Create a fake deb package with equivs-build and the given control file
|
# Create a fake deb package with equivs-build and the given control file
|
||||||
|
@ -190,12 +185,14 @@ ynh_package_install_from_equivs () {
|
||||||
# Install missing dependencies with ynh_package_install
|
# Install missing dependencies with ynh_package_install
|
||||||
ynh_wait_dpkg_free
|
ynh_wait_dpkg_free
|
||||||
cp "$controlfile" "${TMPDIR}/control"
|
cp "$controlfile" "${TMPDIR}/control"
|
||||||
(cd "$TMPDIR"
|
(
|
||||||
LC_ALL=C equivs-build ./control 1> /dev/null
|
cd "$TMPDIR"
|
||||||
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log)
|
LC_ALL=C equivs-build ./control 1>/dev/null
|
||||||
|
LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log
|
||||||
|
)
|
||||||
|
|
||||||
ynh_package_install --fix-broken || \
|
ynh_package_install --fix-broken \
|
||||||
{ # If the installation failed
|
|| { # If the installation failed
|
||||||
# (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process)
|
# (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process)
|
||||||
# Parse the list of problematic dependencies from dpkg's log ...
|
# Parse the list of problematic dependencies from dpkg's log ...
|
||||||
# (relevant lines look like: "foo-ynh-deps depends on bar; however:")
|
# (relevant lines look like: "foo-ynh-deps depends on bar; however:")
|
||||||
|
@ -203,13 +200,16 @@ ynh_package_install_from_equivs () {
|
||||||
# Fake an install of those dependencies to see the errors
|
# Fake an install of those dependencies to see the errors
|
||||||
# The sed command here is, Print only from 'Reading state info' to the end.
|
# The sed command here is, Print only from 'Reading state info' to the end.
|
||||||
[[ -n "$problematic_dependencies" ]] && ynh_package_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2
|
[[ -n "$problematic_dependencies" ]] && ynh_package_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2
|
||||||
ynh_die --message="Unable to install dependencies"; }
|
ynh_die --message="Unable to install dependencies"
|
||||||
|
}
|
||||||
[[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir.
|
[[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir.
|
||||||
|
|
||||||
# check if the package is actually installed
|
# check if the package is actually installed
|
||||||
ynh_package_is_installed "$pkgname"
|
ynh_package_is_installed "$pkgname"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="true"
|
||||||
|
|
||||||
# Define and install dependencies with a equivs control file
|
# Define and install dependencies with a equivs control file
|
||||||
#
|
#
|
||||||
# This helper can/should only be called once per app
|
# This helper can/should only be called once per app
|
||||||
|
@ -221,7 +221,7 @@ ynh_package_install_from_equivs () {
|
||||||
# | arg: "dep1|dep2|…" - You can specify alternatives. It will require to install (dep1 or dep2, etc).
|
# | arg: "dep1|dep2|…" - You can specify alternatives. It will require to install (dep1 or dep2, etc).
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_install_app_dependencies () {
|
ynh_install_app_dependencies() {
|
||||||
local dependencies=$@
|
local dependencies=$@
|
||||||
# Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below)
|
# Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below)
|
||||||
dependencies="$(echo "$dependencies" | sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g')"
|
dependencies="$(echo "$dependencies" | sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g')"
|
||||||
|
@ -235,8 +235,7 @@ ynh_install_app_dependencies () {
|
||||||
local dep_app=${app//_/-} # Replace all '_' by '-'
|
local dep_app=${app//_/-} # Replace all '_' by '-'
|
||||||
|
|
||||||
# Handle specific versions
|
# Handle specific versions
|
||||||
if [[ "$dependencies" =~ [\<=\>] ]]
|
if [[ "$dependencies" =~ [\<=\>] ]]; then
|
||||||
then
|
|
||||||
# Replace version specifications by relationships syntax
|
# Replace version specifications by relationships syntax
|
||||||
# https://www.debian.org/doc/debian-policy/ch-relationships.html
|
# https://www.debian.org/doc/debian-policy/ch-relationships.html
|
||||||
# Sed clarification
|
# Sed clarification
|
||||||
|
@ -248,27 +247,62 @@ ynh_install_app_dependencies () {
|
||||||
dependencies="$(echo "$dependencies" | sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g')"
|
dependencies="$(echo "$dependencies" | sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check for specific php dependencies which requires sury
|
||||||
|
# This grep will for example return "7.4" if dependencies is "foo bar php7.4-pwet php-gni"
|
||||||
|
# The (?<=php) syntax corresponds to lookbehind ;)
|
||||||
|
local specific_php_version=$(echo $dependencies | grep -oP '(?<=php)[0-9.]+(?=-|\>)' | sort -u)
|
||||||
|
|
||||||
|
# Ignore case where the php version found is the one available in debian vanilla
|
||||||
|
[[ "$specific_php_version" != "$YNH_DEFAULT_PHP_VERSION" ]] || specific_php_version=""
|
||||||
|
|
||||||
|
if [[ -n "$specific_php_version" ]]
|
||||||
|
then
|
||||||
|
# Cover a small edge case where a packager could have specified "php7.4-pwet php5-gni" which is confusing
|
||||||
|
[[ $(echo $specific_php_version | wc -l) -eq 1 ]] \
|
||||||
|
|| ynh_die --message="Inconsistent php versions in dependencies ... found : $specific_php_version"
|
||||||
|
|
||||||
|
dependencies+=", php${specific_php_version}, php${specific_php_version}-fpm, php${specific_php_version}-common"
|
||||||
|
|
||||||
|
ynh_add_sury
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# The first time we run ynh_install_app_dependencies, we will replace the
|
||||||
|
# entire control file (This is in particular meant to cover the case of
|
||||||
|
# upgrade script where ynh_install_app_dependencies is called with this
|
||||||
|
# expected effect) Otherwise, any subsequent call will add dependencies
|
||||||
|
# to those already present in the equivs control file.
|
||||||
|
if [[ $YNH_INSTALL_APP_DEPENDENCIES_REPLACE == "true" ]]
|
||||||
|
then
|
||||||
|
YNH_INSTALL_APP_DEPENDENCIES_REPLACE="false"
|
||||||
|
else
|
||||||
|
local current_dependencies=""
|
||||||
|
if ynh_package_is_installed --package="${dep_app}-ynh-deps"
|
||||||
|
then
|
||||||
|
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
|
||||||
|
current_dependencies=${current_dependencies// | /|}
|
||||||
|
fi
|
||||||
|
dependencies="$current_dependencies, $dependencies"
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Epic ugly hack to fix the goddamn dependency nightmare of sury
|
# Epic ugly hack to fix the goddamn dependency nightmare of sury
|
||||||
# Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective
|
# Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective
|
||||||
# https://github.com/YunoHost/issues/issues/1407
|
# https://github.com/YunoHost/issues/issues/1407
|
||||||
#
|
#
|
||||||
# If we require to install php dependency
|
# If we require to install php dependency
|
||||||
if echo $dependencies | grep --quiet 'php'
|
if grep --quiet 'php' <<< "$dependencies"; then
|
||||||
then
|
|
||||||
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
|
# And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian)
|
||||||
if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9"
|
if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9"; then
|
||||||
then
|
|
||||||
# And sury ain't already in sources.lists
|
# And sury ain't already in sources.lists
|
||||||
if ! grep --recursive --quiet "^ *deb.*sury" /etc/apt/sources.list*
|
if ! grep --recursive --quiet "^ *deb.*sury" /etc/apt/sources.list*; then
|
||||||
then
|
|
||||||
# Re-add sury
|
# Re-add sury
|
||||||
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version --priority=600
|
ynh_add_sury
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > /tmp/${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build
|
cat >/tmp/${dep_app}-ynh-deps.control <<EOF # Make a control file for equivs-build
|
||||||
Section: misc
|
Section: misc
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Package: ${dep_app}-ynh-deps
|
Package: ${dep_app}-ynh-deps
|
||||||
|
@ -281,39 +315,55 @@ EOF
|
||||||
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \
|
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \
|
||||||
|| ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
|
|| ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
|
||||||
rm /tmp/${dep_app}-ynh-deps.control
|
rm /tmp/${dep_app}-ynh-deps.control
|
||||||
|
|
||||||
ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies"
|
ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies"
|
||||||
|
|
||||||
|
if [[ -n "$specific_php_version" ]]
|
||||||
|
then
|
||||||
|
# Set the default php version back as the default version for php-cli.
|
||||||
|
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
||||||
|
|
||||||
|
# Store phpversion into the config of this app
|
||||||
|
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
|
||||||
|
|
||||||
|
# Integrate new php-fpm service in yunohost
|
||||||
|
yunohost service add php${specific_php_version}-fpm --log "/var/log/php${phpversion}-fpm.log"
|
||||||
|
elif grep --quiet 'php' <<< "$dependencies"; then
|
||||||
|
# Store phpversion into the config of this app
|
||||||
|
ynh_app_setting_set --app=$app --key=phpversion --value=$YNH_DEFAULT_PHP_VERSION
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add sury repository with adequate pin strategy
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_add_sury
|
||||||
|
#
|
||||||
|
ynh_add_sury() {
|
||||||
|
|
||||||
|
# Add an extra repository for those packages
|
||||||
|
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version --priority=600
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Add dependencies to install with ynh_install_app_dependencies
|
# Add dependencies to install with ynh_install_app_dependencies
|
||||||
#
|
#
|
||||||
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
# usage: ynh_add_app_dependencies --package=phpversion [--replace]
|
||||||
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
# | arg: -p, --package= - Packages to add as dependencies for the app.
|
||||||
# | arg: -r, --replace - Replace dependencies instead of adding to existing ones.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_add_app_dependencies () {
|
ynh_add_app_dependencies() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pr
|
local legacy_args=pr
|
||||||
local -A args_array=( [p]=package= [r]=replace)
|
local -A args_array=([p]=package= [r]=replace)
|
||||||
local package
|
local package
|
||||||
local replace
|
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
replace=${replace:-0}
|
|
||||||
|
|
||||||
local current_dependencies=""
|
ynh_print_warn --message="Packagers: ynh_add_app_dependencies is deprecated and is now only an alias to ynh_install_app_dependencies"
|
||||||
if [ $replace -eq 0 ]
|
ynh_install_app_dependencies "${package}"
|
||||||
then
|
|
||||||
local dep_app=${app//_/-} # Replace all '_' by '-'
|
|
||||||
if ynh_package_is_installed --package="${dep_app}-ynh-deps"
|
|
||||||
then
|
|
||||||
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
|
|
||||||
fi
|
|
||||||
|
|
||||||
current_dependencies=${current_dependencies// | /|}
|
|
||||||
fi
|
|
||||||
|
|
||||||
ynh_install_app_dependencies "${current_dependencies}${package}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove fake package and its dependencies
|
# Remove fake package and its dependencies
|
||||||
|
@ -323,9 +373,26 @@ ynh_add_app_dependencies () {
|
||||||
# usage: ynh_remove_app_dependencies
|
# usage: ynh_remove_app_dependencies
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_remove_app_dependencies () {
|
ynh_remove_app_dependencies() {
|
||||||
local dep_app=${app//_/-} # Replace all '_' by '-'
|
local dep_app=${app//_/-} # Replace all '_' by '-'
|
||||||
|
|
||||||
|
local current_dependencies=""
|
||||||
|
if ynh_package_is_installed --package="${dep_app}-ynh-deps"; then
|
||||||
|
current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) "
|
||||||
|
current_dependencies=${current_dependencies// | /|}
|
||||||
|
fi
|
||||||
|
|
||||||
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
|
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
|
||||||
|
|
||||||
|
# Check if this app used a specific php version ... in which case we check
|
||||||
|
# if the corresponding php-fpm is still there. Otherwise, we remove the
|
||||||
|
# service from yunohost as well
|
||||||
|
|
||||||
|
local specific_php_version=$(echo $current_dependencies | tr '-' ' ' | grep -o -E "\<php[0-9.]+\>" | sed 's/php//g' | sort | uniq)
|
||||||
|
[[ "$specific_php_version" != "$YNH_DEFAULT_PHP_VERSION" ]] || specific_php_version=""
|
||||||
|
if [[ -n "$specific_php_version" ]] && ! ynh_package_is_installed --package="php${specific_php_version}-fpm"; then
|
||||||
|
yunohost service remove php${specific_php_version}-fpm
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install packages from an extra repository properly.
|
# Install packages from an extra repository properly.
|
||||||
|
@ -337,10 +404,10 @@ ynh_remove_app_dependencies () {
|
||||||
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_extra_app_dependencies () {
|
ynh_install_extra_app_dependencies() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rpkn
|
local legacy_args=rpkn
|
||||||
local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= )
|
local -A args_array=([r]=repo= [p]=package= [k]=key= [n]=name=)
|
||||||
local repo
|
local repo
|
||||||
local package
|
local package
|
||||||
local key
|
local key
|
||||||
|
@ -351,15 +418,14 @@ ynh_install_extra_app_dependencies () {
|
||||||
key=${key:-}
|
key=${key:-}
|
||||||
|
|
||||||
# Set a key only if asked
|
# Set a key only if asked
|
||||||
if [ -n "$key" ]
|
if [ -n "$key" ]; then
|
||||||
then
|
|
||||||
key="--key=$key"
|
key="--key=$key"
|
||||||
fi
|
fi
|
||||||
# Add an extra repository for those packages
|
# Add an extra repository for those packages
|
||||||
ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name
|
ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name
|
||||||
|
|
||||||
# Install requested dependencies from this extra repository.
|
# Install requested dependencies from this extra repository.
|
||||||
ynh_add_app_dependencies --package="$package"
|
ynh_install_app_dependencies "$package"
|
||||||
|
|
||||||
# Remove this extra repository after packages are installed
|
# Remove this extra repository after packages are installed
|
||||||
ynh_remove_extra_repo --name=$app
|
ynh_remove_extra_repo --name=$app
|
||||||
|
@ -377,10 +443,10 @@ ynh_install_extra_app_dependencies () {
|
||||||
# | arg: -a, --append - Do not overwrite existing files.
|
# | arg: -a, --append - Do not overwrite existing files.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_extra_repo () {
|
ynh_install_extra_repo() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rkpna
|
local legacy_args=rkpna
|
||||||
local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append )
|
local -A args_array=([r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append)
|
||||||
local repo
|
local repo
|
||||||
local key
|
local key
|
||||||
local priority
|
local priority
|
||||||
|
@ -393,8 +459,7 @@ ynh_install_extra_repo () {
|
||||||
key=${key:-}
|
key=${key:-}
|
||||||
priority=${priority:-}
|
priority=${priority:-}
|
||||||
|
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]; then
|
||||||
then
|
|
||||||
append="--append"
|
append="--append"
|
||||||
wget_append="tee --append"
|
wget_append="tee --append"
|
||||||
else
|
else
|
||||||
|
@ -423,18 +488,16 @@ ynh_install_extra_repo () {
|
||||||
local pin="${uri#*://}"
|
local pin="${uri#*://}"
|
||||||
pin="${pin%%/*}"
|
pin="${pin%%/*}"
|
||||||
# Set a priority only if asked
|
# Set a priority only if asked
|
||||||
if [ -n "$priority" ]
|
if [ -n "$priority" ]; then
|
||||||
then
|
|
||||||
priority="--priority=$priority"
|
priority="--priority=$priority"
|
||||||
fi
|
fi
|
||||||
ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append
|
ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append
|
||||||
|
|
||||||
# Get the public key for the repo
|
# Get the public key for the repo
|
||||||
if [ -n "$key" ]
|
if [ -n "$key" ]; then
|
||||||
then
|
|
||||||
mkdir --parents "/etc/apt/trusted.gpg.d"
|
mkdir --parents "/etc/apt/trusted.gpg.d"
|
||||||
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
# Timeout option is here to enforce the timeout on dns query and tcp connect (c.f. man wget)
|
||||||
wget --timeout 900 --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null
|
wget --timeout 900 --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg >/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update the list of package with the new repo
|
# Update the list of package with the new repo
|
||||||
|
@ -449,10 +512,10 @@ ynh_install_extra_repo () {
|
||||||
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
# | arg: -n, --name= - Name for the files for this repo, $app as default value.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_remove_extra_repo () {
|
ynh_remove_extra_repo() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=n
|
local legacy_args=n
|
||||||
local -A args_array=( [n]=name= )
|
local -A args_array=([n]=name=)
|
||||||
local name
|
local name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -461,8 +524,8 @@ ynh_remove_extra_repo () {
|
||||||
ynh_secure_remove --file="/etc/apt/sources.list.d/$name.list"
|
ynh_secure_remove --file="/etc/apt/sources.list.d/$name.list"
|
||||||
# Sury pinning is managed by the regenconf in the core...
|
# Sury pinning is managed by the regenconf in the core...
|
||||||
[[ "$name" == "extra_php_version" ]] || ynh_secure_remove "/etc/apt/preferences.d/$name"
|
[[ "$name" == "extra_php_version" ]] || ynh_secure_remove "/etc/apt/preferences.d/$name"
|
||||||
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.gpg" > /dev/null
|
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.gpg" >/dev/null
|
||||||
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.asc" > /dev/null
|
ynh_secure_remove --file="/etc/apt/trusted.gpg.d/$name.asc" >/dev/null
|
||||||
|
|
||||||
# Update the list of package to exclude the old repo
|
# Update the list of package to exclude the old repo
|
||||||
ynh_package_update
|
ynh_package_update
|
||||||
|
@ -484,10 +547,10 @@ ynh_remove_extra_repo () {
|
||||||
# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable
|
# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_add_repo () {
|
ynh_add_repo() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uscna
|
local legacy_args=uscna
|
||||||
local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append )
|
local -A args_array=([u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append)
|
||||||
local uri
|
local uri
|
||||||
local suite
|
local suite
|
||||||
local component
|
local component
|
||||||
|
@ -498,8 +561,7 @@ ynh_add_repo () {
|
||||||
name="${name:-$app}"
|
name="${name:-$app}"
|
||||||
append=${append:-0}
|
append=${append:-0}
|
||||||
|
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]; then
|
||||||
then
|
|
||||||
append="tee --append"
|
append="tee --append"
|
||||||
else
|
else
|
||||||
append="tee"
|
append="tee"
|
||||||
|
@ -525,10 +587,10 @@ ynh_add_repo () {
|
||||||
# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning.
|
# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_pin_repo () {
|
ynh_pin_repo() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=pirna
|
local legacy_args=pirna
|
||||||
local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append )
|
local -A args_array=([p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append)
|
||||||
local package
|
local package
|
||||||
local pin
|
local pin
|
||||||
local priority
|
local priority
|
||||||
|
@ -541,8 +603,7 @@ ynh_pin_repo () {
|
||||||
name="${name:-$app}"
|
name="${name:-$app}"
|
||||||
append=${append:-0}
|
append=${append:-0}
|
||||||
|
|
||||||
if [ $append -eq 1 ]
|
if [ $append -eq 1 ]; then
|
||||||
then
|
|
||||||
append="tee --append"
|
append="tee --append"
|
||||||
else
|
else
|
||||||
append="tee"
|
append="tee"
|
||||||
|
|
|
@ -67,7 +67,7 @@ ynh_backup() {
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=sdbm
|
local legacy_args=sdbm
|
||||||
local -A args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory )
|
local -A args_array=([s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory)
|
||||||
local src_path
|
local src_path
|
||||||
local dest_path
|
local dest_path
|
||||||
local is_big
|
local is_big
|
||||||
|
@ -83,10 +83,8 @@ ynh_backup() {
|
||||||
|
|
||||||
# If backing up core only (used by ynh_backup_before_upgrade),
|
# If backing up core only (used by ynh_backup_before_upgrade),
|
||||||
# don't backup big data items
|
# don't backup big data items
|
||||||
if [ $is_big -eq 1 ] && ( [ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ] )
|
if [ $is_big -eq 1 ] && ([ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ]); then
|
||||||
then
|
if [ $BACKUP_CORE_ONLY -eq 1 ]; then
|
||||||
if [ $BACKUP_CORE_ONLY -eq 1 ]
|
|
||||||
then
|
|
||||||
ynh_print_info --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set."
|
ynh_print_info --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set."
|
||||||
else
|
else
|
||||||
ynh_print_info --message="$src_path will not be saved, because 'do_not_backup_data' is set."
|
ynh_print_info --message="$src_path will not be saved, because 'do_not_backup_data' is set."
|
||||||
|
@ -98,14 +96,11 @@ ynh_backup() {
|
||||||
# Format correctly source and destination paths
|
# Format correctly source and destination paths
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Be sure the source path is not empty
|
# Be sure the source path is not empty
|
||||||
if [ ! -e "$src_path" ]
|
if [ ! -e "$src_path" ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="Source path '${src_path}' does not exist"
|
ynh_print_warn --message="Source path '${src_path}' does not exist"
|
||||||
if [ "$not_mandatory" == "0" ]
|
if [ "$not_mandatory" == "0" ]; then
|
||||||
then
|
|
||||||
# This is a temporary fix for fail2ban config files missing after the migration to stretch.
|
# This is a temporary fix for fail2ban config files missing after the migration to stretch.
|
||||||
if echo "${src_path}" | grep --quiet "/etc/fail2ban"
|
if echo "${src_path}" | grep --quiet "/etc/fail2ban"; then
|
||||||
then
|
|
||||||
touch "${src_path}"
|
touch "${src_path}"
|
||||||
ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!"
|
ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!"
|
||||||
else
|
else
|
||||||
|
@ -123,13 +118,11 @@ ynh_backup() {
|
||||||
# If there is no destination path, initialize it with the source path
|
# If there is no destination path, initialize it with the source path
|
||||||
# relative to "/".
|
# relative to "/".
|
||||||
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
|
# eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
|
||||||
if [[ -z "$dest_path" ]]
|
if [[ -z "$dest_path" ]]; then
|
||||||
then
|
|
||||||
dest_path="${src_path#/}"
|
dest_path="${src_path#/}"
|
||||||
|
|
||||||
else
|
else
|
||||||
if [[ "${dest_path:0:1}" == "/" ]]
|
if [[ "${dest_path:0:1}" == "/" ]]; then
|
||||||
then
|
|
||||||
|
|
||||||
# If the destination path is an absolute path, transform it as a path
|
# If the destination path is an absolute path, transform it as a path
|
||||||
# relative to the current working directory ($YNH_CWD)
|
# relative to the current working directory ($YNH_CWD)
|
||||||
|
@ -153,8 +146,7 @@ ynh_backup() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if dest_path already exists in tmp archive
|
# Check if dest_path already exists in tmp archive
|
||||||
if [[ -e "${dest_path}" ]]
|
if [[ -e "${dest_path}" ]]; then
|
||||||
then
|
|
||||||
ynh_print_err --message="Destination path '${dest_path}' already exist"
|
ynh_print_err --message="Destination path '${dest_path}' already exist"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
@ -171,7 +163,7 @@ ynh_backup() {
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g')
|
local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||||
local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g')
|
local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g')
|
||||||
echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}"
|
echo "\"${src}\",\"${dest}\"" >>"${YNH_BACKUP_CSV}"
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
|
@ -185,15 +177,14 @@ ynh_backup() {
|
||||||
# usage: ynh_restore
|
# usage: ynh_restore
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_restore () {
|
ynh_restore() {
|
||||||
# Deduce the relative path of $YNH_CWD
|
# Deduce the relative path of $YNH_CWD
|
||||||
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
|
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
|
||||||
REL_DIR="${REL_DIR%/}/"
|
REL_DIR="${REL_DIR%/}/"
|
||||||
|
|
||||||
# For each destination path begining by $REL_DIR
|
# For each destination path begining by $REL_DIR
|
||||||
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" | \
|
cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" \
|
||||||
while read line
|
| while read line; do
|
||||||
do
|
|
||||||
local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)")
|
local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)")
|
||||||
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
|
local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)")
|
||||||
ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
|
ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
|
||||||
|
@ -205,7 +196,7 @@ ynh_restore () {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: _get_archive_path ORIGIN_PATH
|
# usage: _get_archive_path ORIGIN_PATH
|
||||||
_get_archive_path () {
|
_get_archive_path() {
|
||||||
# For security reasons we use csv python library to read the CSV
|
# For security reasons we use csv python library to read the CSV
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import sys
|
import sys
|
||||||
|
@ -245,10 +236,10 @@ with open(sys.argv[1], 'r') as backup_file:
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
|
# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory
|
||||||
ynh_restore_file () {
|
ynh_restore_file() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=odm
|
local legacy_args=odm
|
||||||
local -A args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory )
|
local -A args_array=([o]=origin_path= [d]=dest_path= [m]=not_mandatory)
|
||||||
local origin_path
|
local origin_path
|
||||||
local dest_path
|
local dest_path
|
||||||
local not_mandatory
|
local not_mandatory
|
||||||
|
@ -261,10 +252,8 @@ ynh_restore_file () {
|
||||||
|
|
||||||
local archive_path="$YNH_CWD${origin_path}"
|
local archive_path="$YNH_CWD${origin_path}"
|
||||||
# If archive_path doesn't exist, search for a corresponding path in CSV
|
# If archive_path doesn't exist, search for a corresponding path in CSV
|
||||||
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]
|
if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
|
||||||
then
|
if [ "$not_mandatory" == "0" ]; then
|
||||||
if [ "$not_mandatory" == "0" ]
|
|
||||||
then
|
|
||||||
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
|
archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -272,11 +261,9 @@ ynh_restore_file () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Move the old directory if it already exists
|
# Move the old directory if it already exists
|
||||||
if [[ -e "${dest_path}" ]]
|
if [[ -e "${dest_path}" ]]; then
|
||||||
then
|
|
||||||
# Check if the file/dir size is less than 500 Mo
|
# Check if the file/dir size is less than 500 Mo
|
||||||
if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]
|
if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]]; then
|
||||||
then
|
|
||||||
local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
mkdir --parents "$(dirname "$backup_file")"
|
mkdir --parents "$(dirname "$backup_file")"
|
||||||
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
mv "${dest_path}" "$backup_file" # Move the current file or directory
|
||||||
|
@ -289,10 +276,8 @@ ynh_restore_file () {
|
||||||
mkdir --parents $(dirname "$dest_path")
|
mkdir --parents $(dirname "$dest_path")
|
||||||
|
|
||||||
# Do a copy if it's just a mounting point
|
# Do a copy if it's just a mounting point
|
||||||
if mountpoint --quiet $YNH_BACKUP_DIR
|
if mountpoint --quiet $YNH_BACKUP_DIR; then
|
||||||
then
|
if [[ -d "${archive_path}" ]]; then
|
||||||
if [[ -d "${archive_path}" ]]
|
|
||||||
then
|
|
||||||
archive_path="${archive_path}/."
|
archive_path="${archive_path}/."
|
||||||
mkdir --parents "$dest_path"
|
mkdir --parents "$dest_path"
|
||||||
fi
|
fi
|
||||||
|
@ -323,10 +308,10 @@ ynh_bind_or_cp() {
|
||||||
# $app should be defined when calling this helper
|
# $app should be defined when calling this helper
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_store_file_checksum () {
|
ynh_store_file_checksum() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
local -A args_array=( [f]=file= [u]=update_only )
|
local -A args_array=([f]=file= [u]=update_only)
|
||||||
local file
|
local file
|
||||||
local update_only
|
local update_only
|
||||||
update_only="${update_only:-0}"
|
update_only="${update_only:-0}"
|
||||||
|
@ -337,9 +322,9 @@ ynh_store_file_checksum () {
|
||||||
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
|
||||||
|
|
||||||
# If update only, we don't save the new checksum if no old checksum exist
|
# If update only, we don't save the new checksum if no old checksum exist
|
||||||
if [ $update_only -eq 1 ] ; then
|
if [ $update_only -eq 1 ]; then
|
||||||
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
|
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
|
||||||
if [ -z "${checksum_value}" ] ; then
|
if [ -z "${checksum_value}" ]; then
|
||||||
unset backup_file_checksum
|
unset backup_file_checksum
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
@ -348,8 +333,7 @@ ynh_store_file_checksum () {
|
||||||
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1)
|
||||||
|
|
||||||
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
# If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup
|
||||||
if [ -n "${backup_file_checksum-}" ]
|
if [ -n "${backup_file_checksum-}" ]; then
|
||||||
then
|
|
||||||
# Print the diff between the previous file and the new one.
|
# Print the diff between the previous file and the new one.
|
||||||
# diff return 1 if the files are different, so the || true
|
# diff return 1 if the files are different, so the || true
|
||||||
diff --report-identical-files --unified --color=always $backup_file_checksum $file >&2 || true
|
diff --report-identical-files --unified --color=always $backup_file_checksum $file >&2 || true
|
||||||
|
@ -368,10 +352,10 @@ ynh_store_file_checksum () {
|
||||||
# modified config files.
|
# modified config files.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_backup_if_checksum_is_different () {
|
ynh_backup_if_checksum_is_different() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
local -A args_array=( [f]=file= )
|
local -A args_array=([f]=file=)
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -380,10 +364,8 @@ ynh_backup_if_checksum_is_different () {
|
||||||
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
|
local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
|
||||||
# backup_file_checksum isn't declare as local, so it can be reuse by ynh_store_file_checksum
|
# backup_file_checksum isn't declare as local, so it can be reuse by ynh_store_file_checksum
|
||||||
backup_file_checksum=""
|
backup_file_checksum=""
|
||||||
if [ -n "$checksum_value" ]
|
if [ -n "$checksum_value" ]; then # Proceed only if a value was stored into the app settings
|
||||||
then # Proceed only if a value was stored into the app settings
|
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status; then # If the checksum is now different
|
||||||
if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status
|
|
||||||
then # If the checksum is now different
|
|
||||||
backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')"
|
||||||
mkdir --parents "$(dirname "$backup_file_checksum")"
|
mkdir --parents "$(dirname "$backup_file_checksum")"
|
||||||
cp --archive "$file" "$backup_file_checksum" # Backup the current file
|
cp --archive "$file" "$backup_file_checksum" # Backup the current file
|
||||||
|
@ -401,10 +383,10 @@ ynh_backup_if_checksum_is_different () {
|
||||||
# $app should be defined when calling this helper
|
# $app should be defined when calling this helper
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.3.1 or higher.
|
# Requires YunoHost version 3.3.1 or higher.
|
||||||
ynh_delete_file_checksum () {
|
ynh_delete_file_checksum() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
local -A args_array=( [f]=file= )
|
local -A args_array=([f]=file=)
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -417,7 +399,7 @@ ynh_delete_file_checksum () {
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
ynh_backup_archive_exists () {
|
ynh_backup_archive_exists() {
|
||||||
yunohost backup list --output-as json --quiet \
|
yunohost backup list --output-as json --quiet \
|
||||||
| jq -e --arg archive "$1" '.archives | index($archive)' >/dev/null
|
| jq -e --arg archive "$1" '.archives | index($archive)' >/dev/null
|
||||||
}
|
}
|
||||||
|
@ -436,9 +418,8 @@ ynh_backup_archive_exists () {
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_backup_before_upgrade () {
|
ynh_backup_before_upgrade() {
|
||||||
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
|
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="This app doesn't have any backup script."
|
ynh_print_warn --message="This app doesn't have any backup script."
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
@ -447,11 +428,9 @@ ynh_backup_before_upgrade () {
|
||||||
local app_bck=${app//_/-} # Replace all '_' by '-'
|
local app_bck=${app//_/-} # Replace all '_' by '-'
|
||||||
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
|
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
|
||||||
|
|
||||||
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]; then
|
||||||
then
|
|
||||||
# Check if a backup already exists with the prefix 1
|
# Check if a backup already exists with the prefix 1
|
||||||
if ynh_backup_archive_exists "$app_bck-pre-upgrade1"
|
if ynh_backup_archive_exists "$app_bck-pre-upgrade1"; then
|
||||||
then
|
|
||||||
# Prefix becomes 2 to preserve the previous backup
|
# Prefix becomes 2 to preserve the previous backup
|
||||||
backup_number=2
|
backup_number=2
|
||||||
old_backup_number=1
|
old_backup_number=1
|
||||||
|
@ -459,13 +438,11 @@ ynh_backup_before_upgrade () {
|
||||||
|
|
||||||
# Create backup
|
# Create backup
|
||||||
BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
|
BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
|
||||||
if [ "$?" -eq 0 ]
|
if [ "$?" -eq 0 ]; then
|
||||||
then
|
|
||||||
# If the backup succeeded, remove the previous backup
|
# If the backup succeeded, remove the previous backup
|
||||||
if ynh_backup_archive_exists "$app_bck-pre-upgrade$old_backup_number"
|
if ynh_backup_archive_exists "$app_bck-pre-upgrade$old_backup_number"; then
|
||||||
then
|
|
||||||
# Remove the previous backup only if it exists
|
# Remove the previous backup only if it exists
|
||||||
yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
|
yunohost backup delete $app_bck-pre-upgrade$old_backup_number >/dev/null
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
ynh_die --message="Backup failed, the upgrade process was aborted."
|
ynh_die --message="Backup failed, the upgrade process was aborted."
|
||||||
|
@ -489,17 +466,15 @@ ynh_backup_before_upgrade () {
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_restore_upgradebackup () {
|
ynh_restore_upgradebackup() {
|
||||||
ynh_print_err --message="Upgrade failed."
|
ynh_print_err --message="Upgrade failed."
|
||||||
local app_bck=${app//_/-} # Replace all '_' by '-'
|
local app_bck=${app//_/-} # Replace all '_' by '-'
|
||||||
|
|
||||||
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
|
NO_BACKUP_UPGRADE=${NO_BACKUP_UPGRADE:-0}
|
||||||
|
|
||||||
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]
|
if [ "$NO_BACKUP_UPGRADE" -eq 0 ]; then
|
||||||
then
|
|
||||||
# Check if an existing backup can be found before removing and restoring the application.
|
# Check if an existing backup can be found before removing and restoring the application.
|
||||||
if ynh_backup_archive_exists "$app_bck-pre-upgrade$backup_number"
|
if ynh_backup_archive_exists "$app_bck-pre-upgrade$backup_number"; then
|
||||||
then
|
|
||||||
# Remove the application then restore it
|
# Remove the application then restore it
|
||||||
yunohost app remove $app
|
yunohost app remove $app
|
||||||
# Restore the backup
|
# Restore the backup
|
||||||
|
|
|
@ -1,10 +1,136 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
_ynh_app_config_get_one() {
|
||||||
|
local short_setting="$1"
|
||||||
|
local type="$2"
|
||||||
|
local bind="$3"
|
||||||
|
local getter="get__${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 [[ "$bind" == *"("* ]] && type -t "get__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||||
|
old[$short_setting]="$("get__${bind%%(*}" $short_setting $type $bind)"
|
||||||
|
formats[${short_setting}]="yaml"
|
||||||
|
|
||||||
|
elif [[ "$bind" == "null" ]]; then
|
||||||
|
old[$short_setting]="YNH_NULL"
|
||||||
|
|
||||||
|
# Get value from app settings or from another file
|
||||||
|
elif [[ "$type" == "file" ]]; then
|
||||||
|
if [[ "$bind" == "settings" ]]; then
|
||||||
|
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||||
|
fi
|
||||||
|
old[$short_setting]="$(ls "$(echo $bind | 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 [[ "$bind" == "settings" ]]; then
|
||||||
|
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
|
||||||
|
elif [[ "$bind" == *":"* ]]; then
|
||||||
|
ynh_die --message="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 $bind | 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
|
||||||
|
local bind_after=""
|
||||||
|
if [[ "$bind" == "settings" ]]; then
|
||||||
|
bind=":/etc/yunohost/apps/$app/settings.yml"
|
||||||
|
fi
|
||||||
|
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||||
|
bind_key_=${bind_key_:-$short_setting}
|
||||||
|
if [[ "$bind_key_" == *">"* ]]; then
|
||||||
|
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
||||||
|
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
||||||
|
fi
|
||||||
|
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
|
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key_}" --after="${bind_after}")"
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
_ynh_app_config_apply_one() {
|
||||||
|
local short_setting="$1"
|
||||||
|
local setter="set__${short_setting}"
|
||||||
|
local bind="${binds[$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 [[ "$bind" == *"("* ]] && type -t "set__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||||
|
"set__${bind%%(*}" $short_setting $type $bind
|
||||||
|
|
||||||
|
elif [[ "$bind" == "null" ]]; then
|
||||||
|
return
|
||||||
|
|
||||||
|
# Save in a file
|
||||||
|
elif [[ "$type" == "file" ]]; then
|
||||||
|
if [[ "$bind" == "settings" ]]; then
|
||||||
|
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
||||||
|
fi
|
||||||
|
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
|
if [[ "${!short_setting}" == "" ]]; then
|
||||||
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
ynh_secure_remove --file="$bind_file"
|
||||||
|
ynh_delete_file_checksum --file="$bind_file" --update_only
|
||||||
|
ynh_print_info --message="File '$bind_file' removed"
|
||||||
|
else
|
||||||
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
if [[ "${!short_setting}" != "$bind_file" ]]; then
|
||||||
|
cp "${!short_setting}" "$bind_file"
|
||||||
|
fi
|
||||||
|
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||||
|
ynh_print_info --message="File '$bind_file' overwritten with ${!short_setting}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save value in app settings
|
||||||
|
elif [[ "$bind" == "settings" ]]; then
|
||||||
|
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
||||||
|
ynh_print_info --message="Configuration key '$short_setting' edited in app settings"
|
||||||
|
|
||||||
|
# Save multiline text in a file
|
||||||
|
elif [[ "$type" == "text" ]]; then
|
||||||
|
if [[ "$bind" == *":"* ]]; then
|
||||||
|
ynh_die --message="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 bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
echo "${!short_setting}" >"$bind_file"
|
||||||
|
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||||
|
ynh_print_info --message="File '$bind_file' overwritten with the content provided in question '${short_setting}'"
|
||||||
|
|
||||||
|
# Set value into a kind of key/value file
|
||||||
|
else
|
||||||
|
local bind_after=""
|
||||||
|
local bind_key_="$(echo "$bind" | cut -d: -f1)"
|
||||||
|
bind_key_=${bind_key_:-$short_setting}
|
||||||
|
if [[ "$bind_key_" == *">"* ]]; then
|
||||||
|
bind_after="$(echo "${bind_key_}" | cut -d'>' -f1)"
|
||||||
|
bind_key_="$(echo "${bind_key_}" | cut -d'>' -f2)"
|
||||||
|
fi
|
||||||
|
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
||||||
|
|
||||||
|
ynh_backup_if_checksum_is_different --file="$bind_file"
|
||||||
|
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key_}" --value="${!short_setting}" --after="${bind_after}"
|
||||||
|
ynh_store_file_checksum --file="$bind_file" --update_only
|
||||||
|
|
||||||
|
# We stored the info in settings in order to be able to upgrade the app
|
||||||
|
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
||||||
|
ynh_print_info --message="Configuration key '$bind_key_' edited into $bind_file"
|
||||||
|
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
_ynh_app_config_get() {
|
_ynh_app_config_get() {
|
||||||
# From settings
|
# From settings
|
||||||
local lines
|
local lines
|
||||||
lines=$(python3 << EOL
|
lines=$(
|
||||||
|
python3 <<EOL
|
||||||
import toml
|
import toml
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
with open("../config_panel.toml", "r") as f:
|
with open("../config_panel.toml", "r") as f:
|
||||||
|
@ -24,164 +150,29 @@ for panel_name, panel in loaded_toml.items():
|
||||||
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
|
param.get('bind', 'settings' if param.get('type', 'string') != 'file' else 'null')
|
||||||
]))
|
]))
|
||||||
EOL
|
EOL
|
||||||
)
|
)
|
||||||
for line in $lines
|
for line in $lines; do
|
||||||
do
|
|
||||||
# Split line into short_setting, type and bind
|
# Split line into short_setting, type and bind
|
||||||
IFS=';' read short_setting type bind <<< "$line"
|
IFS=';' read short_setting type bind <<<"$line"
|
||||||
local getter="get__${short_setting}"
|
|
||||||
binds[${short_setting}]="$bind"
|
binds[${short_setting}]="$bind"
|
||||||
types[${short_setting}]="$type"
|
types[${short_setting}]="$type"
|
||||||
file_hash[${short_setting}]=""
|
file_hash[${short_setting}]=""
|
||||||
formats[${short_setting}]=""
|
formats[${short_setting}]=""
|
||||||
# Get value from getter if exists
|
ynh_app_config_get_one $short_setting $type $bind
|
||||||
if type -t $getter 2>/dev/null | grep -q '^function$' 2>/dev/null;
|
|
||||||
then
|
|
||||||
old[$short_setting]="$($getter)"
|
|
||||||
formats[${short_setting}]="yaml"
|
|
||||||
|
|
||||||
elif [[ "$bind" == "null" ]]
|
|
||||||
then
|
|
||||||
old[$short_setting]="YNH_NULL"
|
|
||||||
|
|
||||||
# Get value from app settings or from another file
|
|
||||||
elif [[ "$type" == "file" ]]
|
|
||||||
then
|
|
||||||
if [[ "$bind" == "settings" ]]
|
|
||||||
then
|
|
||||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
|
||||||
fi
|
|
||||||
old[$short_setting]="$(ls "$(echo $bind | 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 [[ "$bind" == "settings" ]]
|
|
||||||
then
|
|
||||||
old[$short_setting]="$(ynh_app_setting_get $app $short_setting)"
|
|
||||||
elif [[ "$bind" == *":"* ]]
|
|
||||||
then
|
|
||||||
ynh_die --message="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 $bind | 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
|
|
||||||
local bind_after=""
|
|
||||||
if [[ "$bind" == "settings" ]]
|
|
||||||
then
|
|
||||||
bind=":/etc/yunohost/apps/$app/settings.yml"
|
|
||||||
fi
|
|
||||||
local bind_key="$(echo "$bind" | cut -d: -f1)"
|
|
||||||
bind_key=${bind_key:-$short_setting}
|
|
||||||
if [[ "$bind_key" == *">"* ]];
|
|
||||||
then
|
|
||||||
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
|
|
||||||
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
|
|
||||||
fi
|
|
||||||
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
||||||
old[$short_setting]="$(ynh_read_var_in_file --file="${bind_file}" --key="${bind_key}" --after="${bind_after}")"
|
|
||||||
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ynh_app_config_apply() {
|
_ynh_app_config_apply() {
|
||||||
for short_setting in "${!old[@]}"
|
for short_setting in "${!old[@]}"; do
|
||||||
do
|
ynh_app_config_apply_one $short_setting
|
||||||
local setter="set__${short_setting}"
|
|
||||||
local bind="${binds[$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 [[ "$bind" == "null" ]]
|
|
||||||
then
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Save in a file
|
|
||||||
elif [[ "$type" == "file" ]]
|
|
||||||
then
|
|
||||||
if [[ "$bind" == "settings" ]]
|
|
||||||
then
|
|
||||||
ynh_die --message="File '${short_setting}' can't be stored in settings"
|
|
||||||
fi
|
|
||||||
local bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
||||||
if [[ "${!short_setting}" == "" ]]
|
|
||||||
then
|
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
|
||||||
ynh_secure_remove --file="$bind_file"
|
|
||||||
ynh_delete_file_checksum --file="$bind_file" --update_only
|
|
||||||
ynh_print_info --message="File '$bind_file' removed"
|
|
||||||
else
|
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
|
||||||
if [[ "${!short_setting}" != "$bind_file" ]]
|
|
||||||
then
|
|
||||||
cp "${!short_setting}" "$bind_file"
|
|
||||||
fi
|
|
||||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
|
||||||
ynh_print_info --message="File '$bind_file' overwrited with ${!short_setting}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Save value in app settings
|
|
||||||
elif [[ "$bind" == "settings" ]]
|
|
||||||
then
|
|
||||||
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
|
||||||
ynh_print_info --message="Configuration key '$short_setting' edited in app settings"
|
|
||||||
|
|
||||||
# Save multiline text in a file
|
|
||||||
elif [[ "$type" == "text" ]]
|
|
||||||
then
|
|
||||||
if [[ "$bind" == *":"* ]]
|
|
||||||
then
|
|
||||||
ynh_die --message="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 bind_file="$(echo "$bind" | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
|
||||||
echo "${!short_setting}" > "$bind_file"
|
|
||||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
|
||||||
ynh_print_info --message="File '$bind_file' overwrited with the content you provieded in '${short_setting}' question"
|
|
||||||
|
|
||||||
# Set value into a kind of key/value file
|
|
||||||
else
|
|
||||||
local bind_after=""
|
|
||||||
local bind_key="$(echo "$bind" | cut -d: -f1)"
|
|
||||||
bind_key=${bind_key:-$short_setting}
|
|
||||||
if [[ "$bind_key" == *">"* ]];
|
|
||||||
then
|
|
||||||
bind_after="$(echo "${bind_key}" | cut -d'>' -f1)"
|
|
||||||
bind_key="$(echo "${bind_key}" | cut -d'>' -f2)"
|
|
||||||
fi
|
|
||||||
local bind_file="$(echo "$bind" | cut -d: -f2 | sed s@__FINALPATH__@$final_path@ | sed s/__APP__/$app/)"
|
|
||||||
|
|
||||||
ynh_backup_if_checksum_is_different --file="$bind_file"
|
|
||||||
ynh_write_var_in_file --file="${bind_file}" --key="${bind_key}" --value="${!short_setting}" --after="${bind_after}"
|
|
||||||
ynh_store_file_checksum --file="$bind_file" --update_only
|
|
||||||
|
|
||||||
# We stored the info in settings in order to be able to upgrade the app
|
|
||||||
ynh_app_setting_set --app=$app --key=$short_setting --value="${!short_setting}"
|
|
||||||
ynh_print_info --message="Configuration key '$bind_key' edited into $bind_file"
|
|
||||||
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
_ynh_app_config_show() {
|
_ynh_app_config_show() {
|
||||||
for short_setting in "${!old[@]}"
|
for short_setting in "${!old[@]}"; do
|
||||||
do
|
if [[ "${old[$short_setting]}" != YNH_NULL ]]; then
|
||||||
if [[ "${old[$short_setting]}" != YNH_NULL ]]
|
if [[ "${formats[$short_setting]}" == "yaml" ]]; then
|
||||||
then
|
|
||||||
if [[ "${formats[$short_setting]}" == "yaml" ]]
|
|
||||||
then
|
|
||||||
ynh_return "${short_setting}:"
|
ynh_return "${short_setting}:"
|
||||||
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
ynh_return "$(echo "${old[$short_setting]}" | sed 's/^/ /g')"
|
||||||
else
|
else
|
||||||
|
@ -197,48 +188,39 @@ _ynh_app_config_validate() {
|
||||||
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
|
ynh_script_progression --message="Checking what changed in the new configuration..." --weight=1
|
||||||
local nothing_changed=true
|
local nothing_changed=true
|
||||||
local changes_validated=true
|
local changes_validated=true
|
||||||
for short_setting in "${!old[@]}"
|
for short_setting in "${!old[@]}"; do
|
||||||
do
|
|
||||||
changed[$short_setting]=false
|
changed[$short_setting]=false
|
||||||
if [ -z ${!short_setting+x} ]
|
if [ -z ${!short_setting+x} ]; then
|
||||||
then
|
|
||||||
# Assign the var with the old value in order to allows multiple
|
# Assign the var with the old value in order to allows multiple
|
||||||
# args validation
|
# args validation
|
||||||
declare "$short_setting"="${old[$short_setting]}"
|
declare "$short_setting"="${old[$short_setting]}"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
if [ ! -z "${file_hash[${short_setting}]}" ]
|
if [ ! -z "${file_hash[${short_setting}]}" ]; then
|
||||||
then
|
|
||||||
file_hash[old__$short_setting]=""
|
file_hash[old__$short_setting]=""
|
||||||
file_hash[new__$short_setting]=""
|
file_hash[new__$short_setting]=""
|
||||||
if [ -f "${old[$short_setting]}" ]
|
if [ -f "${old[$short_setting]}" ]; then
|
||||||
then
|
|
||||||
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
|
file_hash[old__$short_setting]=$(sha256sum "${old[$short_setting]}" | cut -d' ' -f1)
|
||||||
if [ -z "${!short_setting}" ]
|
if [ -z "${!short_setting}" ]; then
|
||||||
then
|
|
||||||
changed[$short_setting]=true
|
changed[$short_setting]=true
|
||||||
nothing_changed=false
|
nothing_changed=false
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [ -f "${!short_setting}" ]
|
if [ -f "${!short_setting}" ]; then
|
||||||
then
|
|
||||||
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
|
file_hash[new__$short_setting]=$(sha256sum "${!short_setting}" | cut -d' ' -f1)
|
||||||
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]
|
if [[ "${file_hash[old__$short_setting]}" != "${file_hash[new__$short_setting]}" ]]; then
|
||||||
then
|
|
||||||
changed[$short_setting]=true
|
changed[$short_setting]=true
|
||||||
nothing_changed=false
|
nothing_changed=false
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]
|
if [[ "${!short_setting}" != "${old[$short_setting]}" ]]; then
|
||||||
then
|
|
||||||
changed[$short_setting]=true
|
changed[$short_setting]=true
|
||||||
nothing_changed=false
|
nothing_changed=false
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [[ "$nothing_changed" == "true" ]]
|
if [[ "$nothing_changed" == "true" ]]; then
|
||||||
then
|
|
||||||
ynh_print_info --message="Nothing has changed"
|
ynh_print_info --message="Nothing has changed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
@ -246,16 +228,15 @@ _ynh_app_config_validate() {
|
||||||
# Run validation if something is changed
|
# Run validation if something is changed
|
||||||
ynh_script_progression --message="Validating the new configuration..." --weight=1
|
ynh_script_progression --message="Validating the new configuration..." --weight=1
|
||||||
|
|
||||||
for short_setting in "${!old[@]}"
|
for short_setting in "${!old[@]}"; do
|
||||||
do
|
|
||||||
[[ "${changed[$short_setting]}" == "false" ]] && continue
|
[[ "${changed[$short_setting]}" == "false" ]] && continue
|
||||||
local result=""
|
local result=""
|
||||||
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null;
|
if type -t validate__$short_setting | grep -q '^function$' 2>/dev/null; then
|
||||||
then
|
|
||||||
result="$(validate__$short_setting)"
|
result="$(validate__$short_setting)"
|
||||||
|
elif [[ "$bind" == *"("* ]] && type -t "validate__${bind%%(*}" 2>/dev/null | grep -q '^function$' 2>/dev/null; then
|
||||||
|
"validate__${bind%%(*}" $short_setting
|
||||||
fi
|
fi
|
||||||
if [ -n "$result" ]
|
if [ -n "$result" ]; then
|
||||||
then
|
|
||||||
#
|
#
|
||||||
# Return a yaml such as:
|
# Return a yaml such as:
|
||||||
#
|
#
|
||||||
|
@ -265,8 +246,7 @@ _ynh_app_config_validate() {
|
||||||
#
|
#
|
||||||
# We use changes_validated to know if this is
|
# We use changes_validated to know if this is
|
||||||
# the first validation error
|
# the first validation error
|
||||||
if [[ "$changes_validated" == true ]]
|
if [[ "$changes_validated" == true ]]; then
|
||||||
then
|
|
||||||
ynh_return "validation_errors:"
|
ynh_return "validation_errors:"
|
||||||
fi
|
fi
|
||||||
ynh_return " ${short_setting}: \"$result\""
|
ynh_return " ${short_setting}: \"$result\""
|
||||||
|
@ -276,13 +256,16 @@ _ynh_app_config_validate() {
|
||||||
|
|
||||||
# If validation failed, exit the script right now (instead of going into apply)
|
# If validation failed, exit the script right now (instead of going into apply)
|
||||||
# Yunohost core will pick up the errors returned via ynh_return previously
|
# Yunohost core will pick up the errors returned via ynh_return previously
|
||||||
if [[ "$changes_validated" == "false" ]]
|
if [[ "$changes_validated" == "false" ]]; then
|
||||||
then
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ynh_app_config_get_one() {
|
||||||
|
_ynh_app_config_get_one $1 $2 $3
|
||||||
|
}
|
||||||
|
|
||||||
ynh_app_config_get() {
|
ynh_app_config_get() {
|
||||||
_ynh_app_config_get
|
_ynh_app_config_get
|
||||||
}
|
}
|
||||||
|
@ -295,6 +278,9 @@ ynh_app_config_validate() {
|
||||||
_ynh_app_config_validate
|
_ynh_app_config_validate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ynh_app_config_apply_one() {
|
||||||
|
_ynh_app_config_apply_one $1
|
||||||
|
}
|
||||||
ynh_app_config_apply() {
|
ynh_app_config_apply() {
|
||||||
_ynh_app_config_apply
|
_ynh_app_config_apply
|
||||||
}
|
}
|
||||||
|
@ -325,4 +311,3 @@ ynh_app_config_run() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,10 @@
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_fail2ban_config () {
|
ynh_add_fail2ban_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=lrmptv
|
local legacy_args=lrmptv
|
||||||
local -A args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
local -A args_array=([l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
||||||
local logpath
|
local logpath
|
||||||
local failregex
|
local failregex
|
||||||
local max_retry
|
local max_retry
|
||||||
|
@ -81,8 +81,7 @@ ynh_add_fail2ban_config () {
|
||||||
|
|
||||||
[[ -z "$others_var" ]] || ynh_print_warn --message="Packagers: using --others_var is unecessary since YunoHost 4.2"
|
[[ -z "$others_var" ]] || ynh_print_warn --message="Packagers: using --others_var is unecessary since YunoHost 4.2"
|
||||||
|
|
||||||
if [ $use_template -ne 1 ]
|
if [ $use_template -ne 1 ]; then
|
||||||
then
|
|
||||||
# Usage 1, no template. Build a config file from scratch.
|
# Usage 1, no template. Build a config file from scratch.
|
||||||
test -n "$logpath" || ynh_die --message="ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
|
test -n "$logpath" || ynh_die --message="ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
|
||||||
test -n "$failregex" || ynh_die --message="ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
|
test -n "$failregex" || ynh_die --message="ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
|
||||||
|
@ -94,7 +93,7 @@ port = __PORTS__
|
||||||
filter = __APP__
|
filter = __APP__
|
||||||
logpath = __LOGPATH__
|
logpath = __LOGPATH__
|
||||||
maxretry = __MAX_RETRY__
|
maxretry = __MAX_RETRY__
|
||||||
" > $YNH_APP_BASEDIR/conf/f2b_jail.conf
|
" >$YNH_APP_BASEDIR/conf/f2b_jail.conf
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
[INCLUDES]
|
[INCLUDES]
|
||||||
|
@ -102,7 +101,7 @@ before = common.conf
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = __FAILREGEX__
|
failregex = __FAILREGEX__
|
||||||
ignoreregex =
|
ignoreregex =
|
||||||
" > $YNH_APP_BASEDIR/conf/f2b_filter.conf
|
" >$YNH_APP_BASEDIR/conf/f2b_filter.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_add_config --template="$YNH_APP_BASEDIR/conf/f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/f2b_jail.conf" --destination="/etc/fail2ban/jail.d/$app.conf"
|
||||||
|
@ -111,8 +110,7 @@ ignoreregex =
|
||||||
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd
|
||||||
|
|
||||||
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
|
local fail2ban_error="$(journalctl --no-hostname --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")"
|
||||||
if [[ -n "$fail2ban_error" ]]
|
if [[ -n "$fail2ban_error" ]]; then
|
||||||
then
|
|
||||||
ynh_print_err --message="Fail2ban failed to load the jail for $app"
|
ynh_print_err --message="Fail2ban failed to load the jail for $app"
|
||||||
ynh_print_warn --message="${fail2ban_error#*WARNING}"
|
ynh_print_warn --message="${fail2ban_error#*WARNING}"
|
||||||
fi
|
fi
|
||||||
|
@ -123,7 +121,7 @@ ignoreregex =
|
||||||
# usage: ynh_remove_fail2ban_config
|
# usage: ynh_remove_fail2ban_config
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_remove_fail2ban_config () {
|
ynh_remove_fail2ban_config() {
|
||||||
ynh_secure_remove --file="/etc/fail2ban/jail.d/$app.conf"
|
ynh_secure_remove --file="/etc/fail2ban/jail.d/$app.conf"
|
||||||
ynh_secure_remove --file="/etc/fail2ban/filter.d/$app.conf"
|
ynh_secure_remove --file="/etc/fail2ban/filter.d/$app.conf"
|
||||||
ynh_systemd_action --service_name=fail2ban --action=reload
|
ynh_systemd_action --service_name=fail2ban --action=reload
|
||||||
|
|
|
@ -45,11 +45,10 @@
|
||||||
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
|
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.2 or higher.
|
# Requires YunoHost version 3.2.2 or higher.
|
||||||
ynh_handle_getopts_args () {
|
ynh_handle_getopts_args() {
|
||||||
# Manage arguments only if there's some provided
|
# Manage arguments only if there's some provided
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
if [ $# -ne 0 ]
|
if [ $# -ne 0 ]; then
|
||||||
then
|
|
||||||
# Store arguments in an array to keep each argument separated
|
# Store arguments in an array to keep each argument separated
|
||||||
local arguments=("$@")
|
local arguments=("$@")
|
||||||
|
|
||||||
|
@ -58,14 +57,12 @@ ynh_handle_getopts_args () {
|
||||||
# ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
|
# ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
|
||||||
local getopts_parameters=""
|
local getopts_parameters=""
|
||||||
local option_flag=""
|
local option_flag=""
|
||||||
for option_flag in "${!args_array[@]}"
|
for option_flag in "${!args_array[@]}"; do
|
||||||
do
|
|
||||||
# Concatenate each option_flags of the array to build the string of arguments for getopts
|
# Concatenate each option_flags of the array to build the string of arguments for getopts
|
||||||
# Will looks like 'abcd' for -a -b -c -d
|
# Will looks like 'abcd' for -a -b -c -d
|
||||||
# If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
|
# If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
|
||||||
# Check the last character of the value associate to the option_flag
|
# Check the last character of the value associate to the option_flag
|
||||||
if [ "${args_array[$option_flag]: -1}" = "=" ]
|
if [ "${args_array[$option_flag]: -1}" = "=" ]; then
|
||||||
then
|
|
||||||
# For an option with additionnal values, add a ':' after the letter for getopts.
|
# For an option with additionnal values, add a ':' after the letter for getopts.
|
||||||
getopts_parameters="${getopts_parameters}${option_flag}:"
|
getopts_parameters="${getopts_parameters}${option_flag}:"
|
||||||
else
|
else
|
||||||
|
@ -74,8 +71,7 @@ ynh_handle_getopts_args () {
|
||||||
# Check each argument given to the function
|
# Check each argument given to the function
|
||||||
local arg=""
|
local arg=""
|
||||||
# ${#arguments[@]} is the size of the array
|
# ${#arguments[@]} is the size of the array
|
||||||
for arg in `seq 0 $(( ${#arguments[@]} - 1 ))`
|
for arg in $(seq 0 $((${#arguments[@]} - 1))); do
|
||||||
do
|
|
||||||
# Escape options' values starting with -. Otherwise the - will be considered as another option.
|
# Escape options' values starting with -. Otherwise the - will be considered as another option.
|
||||||
arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}"
|
arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}"
|
||||||
# And replace long option (value of the option_flag) by the short option, the option_flag itself
|
# And replace long option (value of the option_flag) by the short option, the option_flag itself
|
||||||
|
@ -89,10 +85,9 @@ ynh_handle_getopts_args () {
|
||||||
|
|
||||||
# Read and parse all the arguments
|
# Read and parse all the arguments
|
||||||
# Use a function here, to use standart arguments $@ and be able to use shift.
|
# Use a function here, to use standart arguments $@ and be able to use shift.
|
||||||
parse_arg () {
|
parse_arg() {
|
||||||
# Read all arguments, until no arguments are left
|
# Read all arguments, until no arguments are left
|
||||||
while [ $# -ne 0 ]
|
while [ $# -ne 0 ]; do
|
||||||
do
|
|
||||||
# Initialize the index of getopts
|
# Initialize the index of getopts
|
||||||
OPTIND=1
|
OPTIND=1
|
||||||
# Parse with getopts only if the argument begin by -, that means the argument is an option
|
# Parse with getopts only if the argument begin by -, that means the argument is an option
|
||||||
|
@ -100,11 +95,9 @@ ynh_handle_getopts_args () {
|
||||||
local parameter=""
|
local parameter=""
|
||||||
getopts ":$getopts_parameters" parameter || true
|
getopts ":$getopts_parameters" parameter || true
|
||||||
|
|
||||||
if [ "$parameter" = "?" ]
|
if [ "$parameter" = "?" ]; then
|
||||||
then
|
|
||||||
ynh_die --message="Invalid argument: -${OPTARG:-}"
|
ynh_die --message="Invalid argument: -${OPTARG:-}"
|
||||||
elif [ "$parameter" = ":" ]
|
elif [ "$parameter" = ":" ]; then
|
||||||
then
|
|
||||||
ynh_die --message="-$OPTARG parameter requires an argument."
|
ynh_die --message="-$OPTARG parameter requires an argument."
|
||||||
else
|
else
|
||||||
local shift_value=1
|
local shift_value=1
|
||||||
|
@ -115,8 +108,7 @@ ynh_handle_getopts_args () {
|
||||||
local option_var="${args_array[$parameter]%=}"
|
local option_var="${args_array[$parameter]%=}"
|
||||||
# If this option doesn't take values
|
# If this option doesn't take values
|
||||||
# if there's a '=' at the end of the long option name, this option takes values
|
# if there's a '=' at the end of the long option name, this option takes values
|
||||||
if [ "${args_array[$parameter]: -1}" != "=" ]
|
if [ "${args_array[$parameter]: -1}" != "=" ]; then
|
||||||
then
|
|
||||||
# 'eval ${option_var}' will use the content of 'option_var'
|
# 'eval ${option_var}' will use the content of 'option_var'
|
||||||
eval ${option_var}=1
|
eval ${option_var}=1
|
||||||
else
|
else
|
||||||
|
@ -126,41 +118,35 @@ ynh_handle_getopts_args () {
|
||||||
|
|
||||||
# If the first argument is longer than 2 characters,
|
# If the first argument is longer than 2 characters,
|
||||||
# There's a value attached to the option, in the same array cell
|
# There's a value attached to the option, in the same array cell
|
||||||
if [ ${#all_args[0]} -gt 2 ]
|
if [ ${#all_args[0]} -gt 2 ]; then
|
||||||
then
|
|
||||||
# Remove the option and the space, so keep only the value itself.
|
# Remove the option and the space, so keep only the value itself.
|
||||||
all_args[0]="${all_args[0]#-${parameter} }"
|
all_args[0]="${all_args[0]#-${parameter} }"
|
||||||
|
|
||||||
# At this point, if all_args[0] start with "-", then the argument is not well formed
|
# At this point, if all_args[0] start with "-", then the argument is not well formed
|
||||||
if [ "${all_args[0]:0:1}" == "-" ]
|
if [ "${all_args[0]:0:1}" == "-" ]; then
|
||||||
then
|
|
||||||
ynh_die --message="Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?"
|
ynh_die --message="Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?"
|
||||||
fi
|
fi
|
||||||
# Reduce the value of shift, because the option has been removed manually
|
# Reduce the value of shift, because the option has been removed manually
|
||||||
shift_value=$(( shift_value - 1 ))
|
shift_value=$((shift_value - 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Declare the content of option_var as a variable.
|
# Declare the content of option_var as a variable.
|
||||||
eval ${option_var}=""
|
eval ${option_var}=""
|
||||||
# Then read the array value per value
|
# Then read the array value per value
|
||||||
local i
|
local i
|
||||||
for i in `seq 0 $(( ${#all_args[@]} - 1 ))`
|
for i in $(seq 0 $((${#all_args[@]} - 1))); do
|
||||||
do
|
|
||||||
# If this argument is an option, end here.
|
# If this argument is an option, end here.
|
||||||
if [ "${all_args[$i]:0:1}" == "-" ]
|
if [ "${all_args[$i]:0:1}" == "-" ]; then
|
||||||
then
|
|
||||||
# Ignore the first value of the array, which is the option itself
|
# Ignore the first value of the array, which is the option itself
|
||||||
if [ "$i" -ne 0 ]; then
|
if [ "$i" -ne 0 ]; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Ignore empty parameters
|
# Ignore empty parameters
|
||||||
if [ -n "${all_args[$i]}" ]
|
if [ -n "${all_args[$i]}" ]; then
|
||||||
then
|
|
||||||
# Else, add this value to this option
|
# Else, add this value to this option
|
||||||
# Each value will be separated by ';'
|
# Each value will be separated by ';'
|
||||||
if [ -n "${!option_var}" ]
|
if [ -n "${!option_var}" ]; then
|
||||||
then
|
|
||||||
# If there's already another value for this option, add a ; before adding the new value
|
# If there's already another value for this option, add a ; before adding the new value
|
||||||
eval ${option_var}+="\;"
|
eval ${option_var}+="\;"
|
||||||
fi
|
fi
|
||||||
|
@ -177,7 +163,7 @@ ynh_handle_getopts_args () {
|
||||||
|
|
||||||
eval ${option_var}+='"${all_args[$i]}"'
|
eval ${option_var}+='"${all_args[$i]}"'
|
||||||
fi
|
fi
|
||||||
shift_value=$(( shift_value + 1 ))
|
shift_value=$((shift_value + 1))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
@ -190,22 +176,21 @@ ynh_handle_getopts_args () {
|
||||||
|
|
||||||
# LEGACY MODE
|
# LEGACY MODE
|
||||||
# Check if there's getopts arguments
|
# Check if there's getopts arguments
|
||||||
if [ "${arguments[0]:0:1}" != "-" ]
|
if [ "${arguments[0]:0:1}" != "-" ]; then
|
||||||
then
|
|
||||||
# If not, enter in legacy mode and manage the arguments as positionnal ones..
|
# If not, enter in legacy mode and manage the arguments as positionnal ones..
|
||||||
# Dot not echo, to prevent to go through a helper output. But print only in the log.
|
# Dot not echo, to prevent to go through a helper output. But print only in the log.
|
||||||
set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x
|
set -x
|
||||||
|
echo "! Helper used in legacy mode !" >/dev/null
|
||||||
|
set +x
|
||||||
local i
|
local i
|
||||||
for i in `seq 0 $(( ${#arguments[@]} -1 ))`
|
for i in $(seq 0 $((${#arguments[@]} - 1))); do
|
||||||
do
|
|
||||||
# Try to use legacy_args as a list of option_flag of the array args_array
|
# Try to use legacy_args as a list of option_flag of the array args_array
|
||||||
# Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order...
|
# Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order...
|
||||||
# Remove all ':' in getopts_parameters
|
# Remove all ':' in getopts_parameters
|
||||||
getopts_parameters=${legacy_args:-${getopts_parameters//:}}
|
getopts_parameters=${legacy_args:-${getopts_parameters//:/}}
|
||||||
# Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
|
# Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
|
||||||
option_flag=${getopts_parameters:$i:1}
|
option_flag=${getopts_parameters:$i:1}
|
||||||
if [ -z "$option_flag" ]
|
if [ -z "$option_flag" ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
|
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
# | ret: the amount of free ram, in MB (MegaBytes)
|
# | ret: the amount of free ram, in MB (MegaBytes)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_get_ram () {
|
ynh_get_ram() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ftso
|
local legacy_args=ftso
|
||||||
local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
local -A args_array=([f]=free [t]=total [s]=ignore_swap [o]=only_swap)
|
||||||
local free
|
local free
|
||||||
local total
|
local total
|
||||||
local ignore_swap
|
local ignore_swap
|
||||||
|
@ -25,41 +25,34 @@ ynh_get_ram () {
|
||||||
free=${free:-0}
|
free=${free:-0}
|
||||||
total=${total:-0}
|
total=${total:-0}
|
||||||
|
|
||||||
if [ $free -eq $total ]
|
if [ $free -eq $total ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram"
|
ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram"
|
||||||
ram=0
|
ram=0
|
||||||
# Use the total amount of ram
|
# Use the total amount of ram
|
||||||
elif [ $free -eq 1 ]
|
elif [ $free -eq 1 ]; then
|
||||||
then
|
|
||||||
local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}')
|
local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}')
|
||||||
local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}')
|
local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}')
|
||||||
local free_ram_swap=$(( free_ram + free_swap ))
|
local free_ram_swap=$((free_ram + free_swap))
|
||||||
|
|
||||||
# Use the total amount of free ram
|
# Use the total amount of free ram
|
||||||
local ram=$free_ram_swap
|
local ram=$free_ram_swap
|
||||||
if [ $ignore_swap -eq 1 ]
|
if [ $ignore_swap -eq 1 ]; then
|
||||||
then
|
|
||||||
# Use only the amount of free ram
|
# Use only the amount of free ram
|
||||||
ram=$free_ram
|
ram=$free_ram
|
||||||
elif [ $only_swap -eq 1 ]
|
elif [ $only_swap -eq 1 ]; then
|
||||||
then
|
|
||||||
# Use only the amount of free swap
|
# Use only the amount of free swap
|
||||||
ram=$free_swap
|
ram=$free_swap
|
||||||
fi
|
fi
|
||||||
elif [ $total -eq 1 ]
|
elif [ $total -eq 1 ]; then
|
||||||
then
|
|
||||||
local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}')
|
local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}')
|
||||||
local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}')
|
local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}')
|
||||||
local total_ram_swap=$(( total_ram + total_swap ))
|
local total_ram_swap=$((total_ram + total_swap))
|
||||||
|
|
||||||
local ram=$total_ram_swap
|
local ram=$total_ram_swap
|
||||||
if [ $ignore_swap -eq 1 ]
|
if [ $ignore_swap -eq 1 ]; then
|
||||||
then
|
|
||||||
# Use only the amount of free ram
|
# Use only the amount of free ram
|
||||||
ram=$total_ram
|
ram=$total_ram
|
||||||
elif [ $only_swap -eq 1 ]
|
elif [ $only_swap -eq 1 ]; then
|
||||||
then
|
|
||||||
# Use only the amount of free swap
|
# Use only the amount of free swap
|
||||||
ram=$total_swap
|
ram=$total_swap
|
||||||
fi
|
fi
|
||||||
|
@ -79,10 +72,10 @@ ynh_get_ram () {
|
||||||
# | ret: 1 if the ram is under the requirement, 0 otherwise.
|
# | ret: 1 if the ram is under the requirement, 0 otherwise.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_require_ram () {
|
ynh_require_ram() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=rftso
|
local legacy_args=rftso
|
||||||
local -A args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap )
|
local -A args_array=([r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap)
|
||||||
local required
|
local required
|
||||||
local free
|
local free
|
||||||
local total
|
local total
|
||||||
|
@ -100,8 +93,7 @@ ynh_require_ram () {
|
||||||
|
|
||||||
local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap)
|
local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap)
|
||||||
|
|
||||||
if [ $ram -lt $required ]
|
if [ $ram -lt $required ]; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
ynh_die() {
|
ynh_die() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mc
|
local legacy_args=mc
|
||||||
local -A args_array=( [m]=message= [c]=ret_code= )
|
local -A args_array=([m]=message= [c]=ret_code=)
|
||||||
local message
|
local message
|
||||||
local ret_code
|
local ret_code
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -30,7 +30,7 @@ ynh_die() {
|
||||||
ynh_print_info() {
|
ynh_print_info() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
local -A args_array=( [m]=message= )
|
local -A args_array=([m]=message=)
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -38,31 +38,12 @@ ynh_print_info() {
|
||||||
echo "$message" >&$YNH_STDINFO
|
echo "$message" >&$YNH_STDINFO
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ignore the yunohost-cli log to prevent errors with conditional commands
|
|
||||||
#
|
|
||||||
# [internal]
|
|
||||||
#
|
|
||||||
# usage: ynh_no_log COMMAND
|
|
||||||
#
|
|
||||||
# Simply duplicate the log, execute the yunohost command and replace the log without the result of this command
|
|
||||||
# It's a very badly hack...
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
|
||||||
ynh_no_log() {
|
|
||||||
local ynh_cli_log=/var/log/yunohost/yunohost-cli.log
|
|
||||||
cp --archive ${ynh_cli_log} ${ynh_cli_log}-move
|
|
||||||
eval $@
|
|
||||||
local exit_code=$?
|
|
||||||
mv ${ynh_cli_log}-move ${ynh_cli_log}
|
|
||||||
return $exit_code
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main printer, just in case in the future we have to change anything about that.
|
# Main printer, just in case in the future we have to change anything about that.
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_log () {
|
ynh_print_log() {
|
||||||
echo -e "${1}"
|
echo -e "${1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,10 +53,10 @@ ynh_print_log () {
|
||||||
# | arg: -m, --message= - The text to print
|
# | arg: -m, --message= - The text to print
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_warn () {
|
ynh_print_warn() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
local -A args_array=( [m]=message= )
|
local -A args_array=([m]=message=)
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -89,10 +70,10 @@ ynh_print_warn () {
|
||||||
# | arg: -m, --message= - The text to print
|
# | arg: -m, --message= - The text to print
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_err () {
|
ynh_print_err() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
local -A args_array=( [m]=message= )
|
local -A args_array=([m]=message=)
|
||||||
local message
|
local message
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -102,82 +83,119 @@ ynh_print_err () {
|
||||||
|
|
||||||
# Execute a command and print the result as an error
|
# Execute a command and print the result as an error
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_err "your_command [ | other_command ]"
|
# usage: ynh_exec_err your command and args
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# Note that you should NOT quote the command but only prefix it with ynh_exec_err
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_err () {
|
ynh_exec_err() {
|
||||||
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
|
# (because in the past eval was used) ...
|
||||||
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
ynh_print_err "$(eval $@)"
|
ynh_print_err "$(eval $@)"
|
||||||
|
else
|
||||||
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
ynh_print_err "$("$@")"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and print the result as a warning
|
# Execute a command and print the result as a warning
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_warn "your_command [ | other_command ]"
|
# usage: ynh_exec_warn your command and args
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# Note that you should NOT quote the command but only prefix it with ynh_exec_warn
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn () {
|
ynh_exec_warn() {
|
||||||
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
|
# (because in the past eval was used) ...
|
||||||
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
ynh_print_warn "$(eval $@)"
|
ynh_print_warn "$(eval $@)"
|
||||||
|
else
|
||||||
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
ynh_print_warn "$("$@")"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and force the result to be printed on stdout
|
# Execute a command and force the result to be printed on stdout
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_warn_less "your_command [ | other_command ]"
|
# usage: ynh_exec_warn_less your command and args
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# Note that you should NOT quote the command but only prefix it with ynh_exec_warn
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn_less () {
|
ynh_exec_warn_less() {
|
||||||
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
|
# (because in the past eval was used) ...
|
||||||
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ 2>&1
|
eval $@ 2>&1
|
||||||
|
else
|
||||||
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
"$@" 2>&1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and redirect stdout in /dev/null
|
# Execute a command and redirect stdout in /dev/null
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_quiet "your_command [ | other_command ]"
|
# usage: ynh_exec_quiet your command and args
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# Note that you should NOT quote the command but only prefix it with ynh_exec_warn
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_quiet () {
|
ynh_exec_quiet() {
|
||||||
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
|
# (because in the past eval was used) ...
|
||||||
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ > /dev/null
|
eval $@ > /dev/null
|
||||||
|
else
|
||||||
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
"$@" > /dev/null
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and redirect stdout and stderr in /dev/null
|
# Execute a command and redirect stdout and stderr in /dev/null
|
||||||
#
|
#
|
||||||
# usage: ynh_exec_fully_quiet "your_command [ | other_command ]"
|
# usage: ynh_exec_quiet your command and args
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
#
|
#
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
# Note that you should NOT quote the command but only prefix it with ynh_exec_quiet
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_fully_quiet () {
|
ynh_exec_fully_quiet() {
|
||||||
|
# Boring legacy handling for when people calls ynh_exec_* wrapping the command in quotes,
|
||||||
|
# (because in the past eval was used) ...
|
||||||
|
# we detect this by checking that there's no 2nd arg, and $1 contains a space
|
||||||
|
if [[ "$#" -eq 1 ]] && [[ "$1" == *" "* ]]
|
||||||
|
then
|
||||||
eval $@ > /dev/null 2>&1
|
eval $@ > /dev/null 2>&1
|
||||||
|
else
|
||||||
|
# Note that "$@" is used and not $@, c.f. https://unix.stackexchange.com/a/129077
|
||||||
|
"$@" > /dev/null 2>&1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove any logs for all the following commands.
|
# Remove any logs for all the following commands.
|
||||||
#
|
#
|
||||||
# usage: ynh_print_OFF
|
# usage: ynh_print_OFF
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
|
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_OFF () {
|
ynh_print_OFF() {
|
||||||
exec {BASH_XTRACEFD}>/dev/null
|
exec {BASH_XTRACEFD}>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +203,13 @@ ynh_print_OFF () {
|
||||||
#
|
#
|
||||||
# usage: ynh_print_ON
|
# usage: ynh_print_ON
|
||||||
#
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
# Requires YunoHost version 3.2.0 or higher.
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_ON () {
|
ynh_print_ON() {
|
||||||
exec {BASH_XTRACEFD}>&1
|
exec {BASH_XTRACEFD}>&1
|
||||||
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
|
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
|
||||||
echo ynh_print_ON > /dev/null
|
echo ynh_print_ON >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Initial definitions for ynh_script_progression
|
# Initial definitions for ynh_script_progression
|
||||||
|
@ -214,11 +234,11 @@ base_time=$(date +%s)
|
||||||
# | arg: -l, --last - Use for the last call of the helper, to fill the progression bar.
|
# | arg: -l, --last - Use for the last call of the helper, to fill the progression bar.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_script_progression () {
|
ynh_script_progression() {
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mwtl
|
local legacy_args=mwtl
|
||||||
local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
|
local -A args_array=([m]=message= [w]=weight= [t]=time [l]=last)
|
||||||
local message
|
local message
|
||||||
local weight
|
local weight
|
||||||
local time
|
local time
|
||||||
|
@ -232,12 +252,11 @@ ynh_script_progression () {
|
||||||
last=${last:-0}
|
last=${last:-0}
|
||||||
|
|
||||||
# Get execution time since the last $base_time
|
# Get execution time since the last $base_time
|
||||||
local exec_time=$(( $(date +%s) - $base_time ))
|
local exec_time=$(($(date +%s) - $base_time))
|
||||||
base_time=$(date +%s)
|
base_time=$(date +%s)
|
||||||
|
|
||||||
# Compute $max_progression (if we didn't already)
|
# Compute $max_progression (if we didn't already)
|
||||||
if [ "$max_progression" = -1 ]
|
if [ "$max_progression" = -1 ]; then
|
||||||
then
|
|
||||||
# Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented.
|
# Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented.
|
||||||
local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)"
|
local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)"
|
||||||
# Get the number of call with a weight value
|
# Get the number of call with a weight value
|
||||||
|
@ -249,23 +268,22 @@ ynh_script_progression () {
|
||||||
local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')"
|
local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')"
|
||||||
# Each value will be on a different line.
|
# Each value will be on a different line.
|
||||||
# Remove each 'end of line' and replace it by a '+' to sum the values.
|
# Remove each 'end of line' and replace it by a '+' to sum the values.
|
||||||
local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 ))
|
local weight_values=$(($(echo "$weight_valuesA" "$weight_valuesB" | grep -v -E '^\s*$' | tr '\n' '+' | sed 's/+$/+0/g')))
|
||||||
|
|
||||||
# max_progression is a total number of calls to this helper.
|
# max_progression is a total number of calls to this helper.
|
||||||
# Less the number of calls with a weight value.
|
# Less the number of calls with a weight value.
|
||||||
# Plus the total of weight values
|
# Plus the total of weight values
|
||||||
max_progression=$(( $helper_calls - $weight_calls + $weight_values ))
|
max_progression=$(($helper_calls - $weight_calls + $weight_values))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increment each execution of ynh_script_progression in this script by the weight of the previous call.
|
# Increment each execution of ynh_script_progression in this script by the weight of the previous call.
|
||||||
increment_progression=$(( $increment_progression + $previous_weight ))
|
increment_progression=$(($increment_progression + $previous_weight))
|
||||||
# Store the weight of the current call in $previous_weight for next call
|
# Store the weight of the current call in $previous_weight for next call
|
||||||
previous_weight=$weight
|
previous_weight=$weight
|
||||||
|
|
||||||
# Reduce $increment_progression to the size of the scale
|
# Reduce $increment_progression to the size of the scale
|
||||||
if [ $last -eq 0 ]
|
if [ $last -eq 0 ]; then
|
||||||
then
|
local effective_progression=$(($increment_progression * $progress_scale / $max_progression))
|
||||||
local effective_progression=$(( $increment_progression * $progress_scale / $max_progression ))
|
|
||||||
# If last is specified, fill immediately the progression_bar
|
# If last is specified, fill immediately the progression_bar
|
||||||
else
|
else
|
||||||
local effective_progression=$progress_scale
|
local effective_progression=$progress_scale
|
||||||
|
@ -273,19 +291,17 @@ ynh_script_progression () {
|
||||||
|
|
||||||
# Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task
|
# Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task
|
||||||
# expected_progression is the progression expected after the current task
|
# expected_progression is the progression expected after the current task
|
||||||
local expected_progression="$(( ( $increment_progression + $weight ) * $progress_scale / $max_progression - $effective_progression ))"
|
local expected_progression="$((($increment_progression + $weight) * $progress_scale / $max_progression - $effective_progression))"
|
||||||
if [ $last -eq 1 ]
|
if [ $last -eq 1 ]; then
|
||||||
then
|
|
||||||
expected_progression=0
|
expected_progression=0
|
||||||
fi
|
fi
|
||||||
# left_progression is the progression not yet done
|
# left_progression is the progression not yet done
|
||||||
local left_progression="$(( $progress_scale - $effective_progression - $expected_progression ))"
|
local left_progression="$(($progress_scale - $effective_progression - $expected_progression))"
|
||||||
# Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done.
|
# Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done.
|
||||||
local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}"
|
local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}"
|
||||||
|
|
||||||
local print_exec_time=""
|
local print_exec_time=""
|
||||||
if [ $time -eq 1 ]
|
if [ $time -eq 1 ]; then
|
||||||
then
|
|
||||||
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
|
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -299,73 +315,6 @@ ynh_script_progression () {
|
||||||
# usage: ynh_return somedata
|
# usage: ynh_return somedata
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.6.0 or higher.
|
# Requires YunoHost version 3.6.0 or higher.
|
||||||
ynh_return () {
|
ynh_return() {
|
||||||
echo "$1" >> "$YNH_STDRETURN"
|
echo "$1" >>"$YNH_STDRETURN"
|
||||||
}
|
|
||||||
|
|
||||||
# Debugger for app packagers
|
|
||||||
#
|
|
||||||
# usage: ynh_debug [--message=message] [--trace=1/0]
|
|
||||||
# | arg: -m, --message= - The text to print
|
|
||||||
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
|
||||||
ynh_debug () {
|
|
||||||
# Disable set xtrace for the helper itself, to not pollute the debug log
|
|
||||||
set +o xtrace # set +x
|
|
||||||
# Declare an array to define the options of this helper.
|
|
||||||
local legacy_args=mt
|
|
||||||
local -A args_array=( [m]=message= [t]=trace= )
|
|
||||||
local message
|
|
||||||
local trace
|
|
||||||
# Manage arguments with getopts
|
|
||||||
ynh_handle_getopts_args "$@"
|
|
||||||
# Re-disable xtrace, ynh_handle_getopts_args set it back
|
|
||||||
set +o xtrace # set +x
|
|
||||||
message=${message:-}
|
|
||||||
trace=${trace:-}
|
|
||||||
|
|
||||||
if [ -n "$message" ]
|
|
||||||
then
|
|
||||||
ynh_print_log "[Debug] ${message}" >&2
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$trace" == "1" ]
|
|
||||||
then
|
|
||||||
ynh_debug --message="Enable debugging"
|
|
||||||
set +o xtrace # set +x
|
|
||||||
# Get the current file descriptor of xtrace
|
|
||||||
old_bash_xtracefd=$BASH_XTRACEFD
|
|
||||||
# Add the current file name and the line number of any command currently running while tracing.
|
|
||||||
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
|
|
||||||
# Force xtrace to stderr
|
|
||||||
BASH_XTRACEFD=2
|
|
||||||
# Force stdout to stderr
|
|
||||||
exec 1>&2
|
|
||||||
fi
|
|
||||||
if [ "$trace" == "0" ]
|
|
||||||
then
|
|
||||||
ynh_debug --message="Disable debugging"
|
|
||||||
set +o xtrace # set +x
|
|
||||||
# Put xtrace back to its original fild descriptor
|
|
||||||
BASH_XTRACEFD=$old_bash_xtracefd
|
|
||||||
# Restore stdout
|
|
||||||
exec 1>&1
|
|
||||||
fi
|
|
||||||
# Renable set xtrace
|
|
||||||
set -o xtrace # set -x
|
|
||||||
}
|
|
||||||
|
|
||||||
# Execute a command and print the result as debug
|
|
||||||
#
|
|
||||||
# usage: ynh_debug_exec "your_command [ | other_command ]"
|
|
||||||
# | arg: command - command to execute
|
|
||||||
#
|
|
||||||
# When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe.
|
|
||||||
#
|
|
||||||
# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed.
|
|
||||||
#
|
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
|
||||||
ynh_debug_exec () {
|
|
||||||
ynh_debug --message="$(eval $@)"
|
|
||||||
}
|
}
|
|
@ -15,10 +15,10 @@
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
# Requires YunoHost version 3.2.0 or higher for the argument `--specific_user`
|
# Requires YunoHost version 3.2.0 or higher for the argument `--specific_user`
|
||||||
ynh_use_logrotate () {
|
ynh_use_logrotate() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=lnuya
|
local legacy_args=lnuya
|
||||||
local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
|
local -A args_array=([l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append)
|
||||||
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
|
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
|
||||||
local logfile
|
local logfile
|
||||||
local nonappend
|
local nonappend
|
||||||
|
@ -30,22 +30,18 @@ ynh_use_logrotate () {
|
||||||
specific_user="${specific_user:-}"
|
specific_user="${specific_user:-}"
|
||||||
|
|
||||||
# LEGACY CODE - PRE GETOPTS
|
# LEGACY CODE - PRE GETOPTS
|
||||||
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]
|
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
|
||||||
then
|
|
||||||
nonappend=1
|
nonappend=1
|
||||||
# Destroy this argument for the next command.
|
# Destroy this argument for the next command.
|
||||||
shift
|
shift
|
||||||
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]
|
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
|
||||||
then
|
|
||||||
nonappend=1
|
nonappend=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]
|
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
|
||||||
then
|
|
||||||
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
|
# If the given logfile parameter already exists as a file, or if it ends up with ".log",
|
||||||
# we just want to manage a single file
|
# we just want to manage a single file
|
||||||
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]
|
if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then
|
||||||
then
|
|
||||||
local logfile=$1
|
local logfile=$1
|
||||||
# Otherwise we assume we want to manage a directory and all its .log file inside
|
# Otherwise we assume we want to manage a directory and all its .log file inside
|
||||||
else
|
else
|
||||||
|
@ -58,8 +54,7 @@ ynh_use_logrotate () {
|
||||||
if [ "$nonappend" -eq 1 ]; then
|
if [ "$nonappend" -eq 1 ]; then
|
||||||
customtee="tee"
|
customtee="tee"
|
||||||
fi
|
fi
|
||||||
if [ -n "$logfile" ]
|
if [ -n "$logfile" ]; then
|
||||||
then
|
|
||||||
if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
|
if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
|
||||||
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
|
local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it.
|
||||||
fi
|
fi
|
||||||
|
@ -67,13 +62,12 @@ ynh_use_logrotate () {
|
||||||
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
|
logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
|
||||||
fi
|
fi
|
||||||
local su_directive=""
|
local su_directive=""
|
||||||
if [[ -n $specific_user ]]
|
if [[ -n $specific_user ]]; then
|
||||||
then
|
|
||||||
su_directive=" # Run logorotate as specific user - group
|
su_directive=" # Run logorotate as specific user - group
|
||||||
su ${specific_user%/*} ${specific_user#*/}"
|
su ${specific_user%/*} ${specific_user#*/}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > ./${app}-logrotate << EOF # Build a config file for logrotate
|
cat >./${app}-logrotate <<EOF # Build a config file for logrotate
|
||||||
$logfile {
|
$logfile {
|
||||||
# Rotate if the logfile exceeds 100Mo
|
# Rotate if the logfile exceeds 100Mo
|
||||||
size 100M
|
size 100M
|
||||||
|
@ -95,7 +89,12 @@ $logfile {
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist
|
mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist
|
||||||
cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
|
cat ${app}-logrotate | $customtee /etc/logrotate.d/$app >/dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee)
|
||||||
|
|
||||||
|
if ynh_user_exists --username="$app"; then
|
||||||
|
chown $app:$app "$logfile"
|
||||||
|
chmod o-rwx "$logfile"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the app's logrotate config.
|
# Remove the app's logrotate config.
|
||||||
|
@ -103,7 +102,7 @@ EOF
|
||||||
# usage: ynh_remove_logrotate
|
# usage: ynh_remove_logrotate
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_remove_logrotate () {
|
ynh_remove_logrotate() {
|
||||||
if [ -e "/etc/logrotate.d/$app" ]; then
|
if [ -e "/etc/logrotate.d/$app" ]; then
|
||||||
rm "/etc/logrotate.d/$app"
|
rm "/etc/logrotate.d/$app"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -22,8 +22,7 @@ ynh_multimedia_build_main_dir() {
|
||||||
mkdir -p "$MEDIA_DIRECTORY/share/eBook"
|
mkdir -p "$MEDIA_DIRECTORY/share/eBook"
|
||||||
|
|
||||||
## Création des dossiers utilisateurs
|
## Création des dossiers utilisateurs
|
||||||
for user in $(yunohost user list --output-as json | jq -r '.users | keys[]')
|
for user in $(yunohost user list --output-as json | jq -r '.users | keys[]'); do
|
||||||
do
|
|
||||||
mkdir -p "$MEDIA_DIRECTORY/$user"
|
mkdir -p "$MEDIA_DIRECTORY/$user"
|
||||||
mkdir -p "$MEDIA_DIRECTORY/$user/Music"
|
mkdir -p "$MEDIA_DIRECTORY/$user/Music"
|
||||||
mkdir -p "$MEDIA_DIRECTORY/$user/Picture"
|
mkdir -p "$MEDIA_DIRECTORY/$user/Picture"
|
||||||
|
@ -66,7 +65,7 @@ ynh_multimedia_addfolder() {
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=sd
|
local legacy_args=sd
|
||||||
local -A args_array=( [s]=source_dir= [d]=dest_dir= )
|
local -A args_array=([s]=source_dir= [d]=dest_dir=)
|
||||||
local source_dir
|
local source_dir
|
||||||
local dest_dir
|
local dest_dir
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -91,10 +90,10 @@ ynh_multimedia_addfolder() {
|
||||||
# | arg: -u, --user_name= - The name of the user which gain this access.
|
# | arg: -u, --user_name= - The name of the user which gain this access.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.2 or higher.
|
# Requires YunoHost version 4.2 or higher.
|
||||||
ynh_multimedia_addaccess () {
|
ynh_multimedia_addaccess() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
declare -Ar args_array=( [u]=user_name=)
|
declare -Ar args_array=([u]=user_name=)
|
||||||
local user_name
|
local user_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
ynh_mysql_connect_as() {
|
ynh_mysql_connect_as() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=upd
|
local legacy_args=upd
|
||||||
local -A args_array=( [u]=user= [p]=password= [d]=database= )
|
local -A args_array=([u]=user= [p]=password= [d]=database=)
|
||||||
local user
|
local user
|
||||||
local password
|
local password
|
||||||
local database
|
local database
|
||||||
|
@ -36,19 +36,18 @@ ynh_mysql_connect_as() {
|
||||||
ynh_mysql_execute_as_root() {
|
ynh_mysql_execute_as_root() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=sd
|
local legacy_args=sd
|
||||||
local -A args_array=( [s]=sql= [d]=database= )
|
local -A args_array=([s]=sql= [d]=database=)
|
||||||
local sql
|
local sql
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
database="${database:-}"
|
database="${database:-}"
|
||||||
|
|
||||||
if [ -n "$database" ]
|
if [ -n "$database" ]; then
|
||||||
then
|
|
||||||
database="--database=$database"
|
database="--database=$database"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mysql -B "$database" <<< "$sql"
|
mysql -B "$database" <<<"$sql"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command from a file as root user
|
# Execute a command from a file as root user
|
||||||
|
@ -61,19 +60,18 @@ ynh_mysql_execute_as_root() {
|
||||||
ynh_mysql_execute_file_as_root() {
|
ynh_mysql_execute_file_as_root() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fd
|
local legacy_args=fd
|
||||||
local -A args_array=( [f]=file= [d]=database= )
|
local -A args_array=([f]=file= [d]=database=)
|
||||||
local file
|
local file
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
database="${database:-}"
|
database="${database:-}"
|
||||||
|
|
||||||
if [ -n "$database" ]
|
if [ -n "$database" ]; then
|
||||||
then
|
|
||||||
database="--database=$database"
|
database="--database=$database"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mysql -B "$database" < "$file"
|
mysql -B "$database" <"$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a database and grant optionnaly privilegies to a user
|
# Create a database and grant optionnaly privilegies to a user
|
||||||
|
@ -92,8 +90,7 @@ ynh_mysql_create_db() {
|
||||||
local sql="CREATE DATABASE ${db};"
|
local sql="CREATE DATABASE ${db};"
|
||||||
|
|
||||||
# grant all privilegies to user
|
# grant all privilegies to user
|
||||||
if [[ $# -gt 1 ]]
|
if [[ $# -gt 1 ]]; then
|
||||||
then
|
|
||||||
sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'"
|
sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'"
|
||||||
if [[ -n ${3:-} ]]; then
|
if [[ -n ${3:-} ]]; then
|
||||||
sql+=" IDENTIFIED BY '${3}'"
|
sql+=" IDENTIFIED BY '${3}'"
|
||||||
|
@ -131,7 +128,7 @@ ynh_mysql_drop_db() {
|
||||||
ynh_mysql_dump_db() {
|
ynh_mysql_dump_db() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=d
|
local legacy_args=d
|
||||||
local -A args_array=( [d]=database= )
|
local -A args_array=([d]=database=)
|
||||||
local database
|
local database
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -160,17 +157,15 @@ ynh_mysql_create_user() {
|
||||||
# | ret: 0 if the user exists, 1 otherwise.
|
# | ret: 0 if the user exists, 1 otherwise.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_user_exists()
|
ynh_mysql_user_exists() {
|
||||||
{
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
local -A args_array=( [u]=user= )
|
local -A args_array=([u]=user=)
|
||||||
local user
|
local user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]]
|
if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]]; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -200,10 +195,10 @@ ynh_mysql_drop_user() {
|
||||||
# It will also be stored as "`mysqlpwd`" into the app settings.
|
# It will also be stored as "`mysqlpwd`" into the app settings.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_mysql_setup_db () {
|
ynh_mysql_setup_db() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=unp
|
local legacy_args=unp
|
||||||
local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
|
local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=)
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
db_pwd=""
|
db_pwd=""
|
||||||
|
@ -226,10 +221,10 @@ ynh_mysql_setup_db () {
|
||||||
# | arg: -n, --db_name= - Name of the database
|
# | arg: -n, --db_name= - Name of the database
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_mysql_remove_db () {
|
ynh_mysql_remove_db() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=un
|
local legacy_args=un
|
||||||
local -Ar args_array=( [u]=db_user= [n]=db_name= )
|
local -Ar args_array=([u]=db_user= [n]=db_name=)
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
|
|
@ -9,18 +9,17 @@
|
||||||
# example: port=$(ynh_find_port --port=8080)
|
# example: port=$(ynh_find_port --port=8080)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_find_port () {
|
ynh_find_port() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=port= )
|
local -A args_array=([p]=port=)
|
||||||
local port
|
local port
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
|
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
|
||||||
while ! ynh_port_available --port=$port
|
while ! ynh_port_available --port=$port; do
|
||||||
do
|
port=$((port + 1))
|
||||||
port=$((port+1))
|
|
||||||
done
|
done
|
||||||
echo $port
|
echo $port
|
||||||
}
|
}
|
||||||
|
@ -34,28 +33,25 @@ ynh_find_port () {
|
||||||
# example: ynh_port_available --port=1234 || ynh_die --message="Port 1234 is needs to be available for this app"
|
# example: ynh_port_available --port=1234 || ynh_die --message="Port 1234 is needs to be available for this app"
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.0 or higher.
|
# Requires YunoHost version 3.8.0 or higher.
|
||||||
ynh_port_available () {
|
ynh_port_available() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=port= )
|
local -A args_array=([p]=port=)
|
||||||
local port
|
local port
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# Check if the port is free
|
# Check if the port is free
|
||||||
if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$"
|
if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$"; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
# This is to cover (most) case where an app is using a port yet ain't currently using it for some reason (typically service ain't up)
|
# This is to cover (most) case where an app is using a port yet ain't currently using it for some reason (typically service ain't up)
|
||||||
elif grep -q "port: '$port'" /etc/yunohost/apps/*/settings.yml
|
elif grep -q "port: '$port'" /etc/yunohost/apps/*/settings.yml; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Validate an IP address
|
# Validate an IP address
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
|
@ -66,13 +62,12 @@ ynh_port_available () {
|
||||||
# example: ynh_validate_ip 4 111.222.333.444
|
# example: ynh_validate_ip 4 111.222.333.444
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip()
|
ynh_validate_ip() {
|
||||||
{
|
|
||||||
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
|
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fi
|
local legacy_args=fi
|
||||||
local -A args_array=( [f]=family= [i]=ip_address= )
|
local -A args_array=([f]=family= [i]=ip_address=)
|
||||||
local family
|
local family
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -80,7 +75,7 @@ ynh_validate_ip()
|
||||||
|
|
||||||
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1
|
[ "$family" == "4" ] || [ "$family" == "6" ] || return 1
|
||||||
|
|
||||||
python3 /dev/stdin << EOF
|
python3 /dev/stdin <<EOF
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
|
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
|
||||||
|
@ -101,11 +96,10 @@ EOF
|
||||||
# example: ynh_validate_ip4 111.222.333.444
|
# example: ynh_validate_ip4 111.222.333.444
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip4()
|
ynh_validate_ip4() {
|
||||||
{
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=i
|
local legacy_args=i
|
||||||
local -A args_array=( [i]=ip_address= )
|
local -A args_array=([i]=ip_address=)
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -113,7 +107,6 @@ ynh_validate_ip4()
|
||||||
ynh_validate_ip --family=4 --ip_address=$ip_address
|
ynh_validate_ip --family=4 --ip_address=$ip_address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Validate an IPv6 address
|
# Validate an IPv6 address
|
||||||
#
|
#
|
||||||
# usage: ynh_validate_ip6 --ip_address=ip_address
|
# usage: ynh_validate_ip6 --ip_address=ip_address
|
||||||
|
@ -123,11 +116,10 @@ ynh_validate_ip4()
|
||||||
# example: ynh_validate_ip6 2000:dead:beef::1
|
# example: ynh_validate_ip6 2000:dead:beef::1
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip6()
|
ynh_validate_ip6() {
|
||||||
{
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=i
|
local legacy_args=i
|
||||||
local -A args_array=( [i]=ip_address= )
|
local -A args_array=([i]=ip_address=)
|
||||||
local ip_address
|
local ip_address
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
# location
|
# location
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_nginx_config () {
|
ynh_add_nginx_config() {
|
||||||
|
|
||||||
local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
local finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
|
|
||||||
if [ "${path_url:-}" != "/" ]
|
if [ "${path_url:-}" != "/" ]; then
|
||||||
then
|
|
||||||
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
||||||
else
|
else
|
||||||
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$YNH_APP_BASEDIR/conf/nginx.conf"
|
||||||
|
@ -29,7 +28,6 @@ ynh_add_nginx_config () {
|
||||||
|
|
||||||
ynh_add_config --template="$YNH_APP_BASEDIR/conf/nginx.conf" --destination="$finalnginxconf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/nginx.conf" --destination="$finalnginxconf"
|
||||||
|
|
||||||
|
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +36,7 @@ ynh_add_nginx_config () {
|
||||||
# usage: ynh_remove_nginx_config
|
# usage: ynh_remove_nginx_config
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_remove_nginx_config () {
|
ynh_remove_nginx_config() {
|
||||||
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
ynh_systemd_action --service_name=nginx --action=reload
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
n_version=7.3.0
|
n_version=7.5.0
|
||||||
n_install_dir="/opt/node_n"
|
n_install_dir="/opt/node_n"
|
||||||
node_version_path="$n_install_dir/n/versions/node"
|
node_version_path="$n_install_dir/n/versions/node"
|
||||||
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
|
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
|
||||||
|
@ -13,16 +13,18 @@ export N_PREFIX="$n_install_dir"
|
||||||
# usage: ynh_install_n
|
# usage: ynh_install_n
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_install_n () {
|
ynh_install_n() {
|
||||||
ynh_print_info --message="Installation of N - Node.js version management"
|
ynh_print_info --message="Installation of N - Node.js version management"
|
||||||
# Build an app.src for n
|
# Build an app.src for n
|
||||||
echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz
|
echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz
|
||||||
SOURCE_SUM=b908b0fc86922ede37e89d1030191285209d7d521507bf136e62895e5797847f" > "$YNH_APP_BASEDIR/conf/n.src"
|
SOURCE_SUM=d4da7ea91f680de0c9b5876e097e2a793e8234fcd0f7ca87a0599b925be087a3" >"$YNH_APP_BASEDIR/conf/n.src"
|
||||||
# Download and extract n
|
# Download and extract n
|
||||||
ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
|
ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
|
||||||
# Install n
|
# Install n
|
||||||
(cd "$n_install_dir/git"
|
(
|
||||||
PREFIX=$N_PREFIX make install 2>&1)
|
cd "$n_install_dir/git"
|
||||||
|
PREFIX=$N_PREFIX make install 2>&1
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load the version of node for an app, and set variables.
|
# Load the version of node for an app, and set variables.
|
||||||
|
@ -69,7 +71,7 @@ SOURCE_SUM=b908b0fc86922ede37e89d1030191285209d7d521507bf136e62895e5797847f" > "
|
||||||
# - $nodejs_version: Just the version number of node for this app. Stored as 'nodejs_version' in settings.yml.
|
# - $nodejs_version: Just the version number of node for this app. Stored as 'nodejs_version' in settings.yml.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_use_nodejs () {
|
ynh_use_nodejs() {
|
||||||
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
||||||
|
|
||||||
# Get the absolute path of this version of node
|
# Get the absolute path of this version of node
|
||||||
|
@ -109,12 +111,12 @@ ynh_use_nodejs () {
|
||||||
# Refer to `ynh_use_nodejs` for more information about available commands and variables
|
# Refer to `ynh_use_nodejs` for more information about available commands and variables
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_install_nodejs () {
|
ynh_install_nodejs() {
|
||||||
# Use n, https://github.com/tj/n to manage the nodejs versions
|
# Use n, https://github.com/tj/n to manage the nodejs versions
|
||||||
|
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=n
|
local legacy_args=n
|
||||||
local -A args_array=( [n]=nodejs_version= )
|
local -A args_array=([n]=nodejs_version=)
|
||||||
local nodejs_version
|
local nodejs_version
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -132,11 +134,9 @@ ynh_install_nodejs () {
|
||||||
test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n
|
test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n
|
||||||
|
|
||||||
# If n is not previously setup, install it
|
# If n is not previously setup, install it
|
||||||
if ! $n_install_dir/bin/n --version > /dev/null 2>&1
|
if ! $n_install_dir/bin/n --version >/dev/null 2>&1; then
|
||||||
then
|
|
||||||
ynh_install_n
|
ynh_install_n
|
||||||
elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version
|
elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version; then
|
||||||
then
|
|
||||||
ynh_install_n
|
ynh_install_n
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -152,8 +152,7 @@ ynh_install_nodejs () {
|
||||||
|
|
||||||
# Install the requested version of nodejs
|
# Install the requested version of nodejs
|
||||||
uname=$(uname --machine)
|
uname=$(uname --machine)
|
||||||
if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
|
if [[ $uname =~ aarch64 || $uname =~ arm64 ]]; then
|
||||||
then
|
|
||||||
n $nodejs_version --arch=arm64
|
n $nodejs_version --arch=arm64
|
||||||
else
|
else
|
||||||
n $nodejs_version
|
n $nodejs_version
|
||||||
|
@ -164,8 +163,7 @@ ynh_install_nodejs () {
|
||||||
real_nodejs_version=$(basename $real_nodejs_version)
|
real_nodejs_version=$(basename $real_nodejs_version)
|
||||||
|
|
||||||
# Create a symbolic link for this major version if the file doesn't already exist
|
# Create a symbolic link for this major version if the file doesn't already exist
|
||||||
if [ ! -e "$node_version_path/$nodejs_version" ]
|
if [ ! -e "$node_version_path/$nodejs_version" ]; then
|
||||||
then
|
|
||||||
ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version
|
ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -190,21 +188,19 @@ ynh_install_nodejs () {
|
||||||
# - If no other app uses node, n will be also removed.
|
# - If no other app uses node, n will be also removed.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_remove_nodejs () {
|
ynh_remove_nodejs() {
|
||||||
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
|
||||||
|
|
||||||
# Remove the line for this app
|
# Remove the line for this app
|
||||||
sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
||||||
|
|
||||||
# If no other app uses this version of nodejs, remove it.
|
# If no other app uses this version of nodejs, remove it.
|
||||||
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"
|
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"; then
|
||||||
then
|
|
||||||
$n_install_dir/bin/n rm $nodejs_version
|
$n_install_dir/bin/n rm $nodejs_version
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If no other app uses n, remove n
|
# If no other app uses n, remove n
|
||||||
if [ ! -s "$n_install_dir/ynh_app_version" ]
|
if [ ! -s "$n_install_dir/ynh_app_version" ]; then
|
||||||
then
|
|
||||||
ynh_secure_remove --file="$n_install_dir"
|
ynh_secure_remove --file="$n_install_dir"
|
||||||
ynh_secure_remove --file="/usr/local/n"
|
ynh_secure_remove --file="/usr/local/n"
|
||||||
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
sed --in-place "/N_PREFIX/d" /root/.bashrc
|
||||||
|
@ -221,9 +217,9 @@ ynh_remove_nodejs () {
|
||||||
# usage: ynh_cron_upgrade_node
|
# usage: ynh_cron_upgrade_node
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_cron_upgrade_node () {
|
ynh_cron_upgrade_node() {
|
||||||
# Build the update script
|
# Build the update script
|
||||||
cat > "$n_install_dir/node_update.sh" << EOF
|
cat >"$n_install_dir/node_update.sh" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
version_path="$node_version_path"
|
version_path="$node_version_path"
|
||||||
|
@ -259,7 +255,7 @@ EOF
|
||||||
chmod +x "$n_install_dir/node_update.sh"
|
chmod +x "$n_install_dir/node_update.sh"
|
||||||
|
|
||||||
# Build the cronjob
|
# Build the cronjob
|
||||||
cat > "/etc/cron.daily/node_update" << EOF
|
cat >"/etc/cron.daily/node_update" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
$n_install_dir/node_update.sh >> $n_install_dir/node_update.log
|
$n_install_dir/node_update.sh >> $n_install_dir/node_update.log
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
ynh_permission_create() {
|
ynh_permission_create() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=puAhaltP
|
local legacy_args=puAhaltP
|
||||||
local -A args_array=( [p]=permission= [u]=url= [A]=additional_urls= [h]=auth_header= [a]=allowed= [l]=label= [t]=show_tile= [P]=protected= )
|
local -A args_array=([p]=permission= [u]=url= [A]=additional_urls= [h]=auth_header= [a]=allowed= [l]=label= [t]=show_tile= [P]=protected=)
|
||||||
local permission
|
local permission
|
||||||
local url
|
local url
|
||||||
local additional_urls
|
local additional_urls
|
||||||
|
@ -84,13 +84,11 @@ ynh_permission_create() {
|
||||||
show_tile=${show_tile:-}
|
show_tile=${show_tile:-}
|
||||||
protected=${protected:-}
|
protected=${protected:-}
|
||||||
|
|
||||||
if [[ -n $url ]]
|
if [[ -n $url ]]; then
|
||||||
then
|
|
||||||
url=",url='$url'"
|
url=",url='$url'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $additional_urls ]]
|
if [[ -n $additional_urls ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# By example:
|
# By example:
|
||||||
|
@ -100,18 +98,15 @@ ynh_permission_create() {
|
||||||
additional_urls=",additional_urls=['${additional_urls//;/\',\'}']"
|
additional_urls=",additional_urls=['${additional_urls//;/\',\'}']"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $auth_header ]]
|
if [[ -n $auth_header ]]; then
|
||||||
then
|
if [ $auth_header == "true" ]; then
|
||||||
if [ $auth_header == "true" ]
|
|
||||||
then
|
|
||||||
auth_header=",auth_header=True"
|
auth_header=",auth_header=True"
|
||||||
else
|
else
|
||||||
auth_header=",auth_header=False"
|
auth_header=",auth_header=False"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $allowed ]]
|
if [[ -n $allowed ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# By example:
|
# By example:
|
||||||
|
@ -127,20 +122,16 @@ ynh_permission_create() {
|
||||||
label=",label='$permission'"
|
label=",label='$permission'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n ${show_tile:-} ]]
|
if [[ -n ${show_tile:-} ]]; then
|
||||||
then
|
if [ $show_tile == "true" ]; then
|
||||||
if [ $show_tile == "true" ]
|
|
||||||
then
|
|
||||||
show_tile=",show_tile=True"
|
show_tile=",show_tile=True"
|
||||||
else
|
else
|
||||||
show_tile=",show_tile=False"
|
show_tile=",show_tile=False"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n ${protected:-} ]]
|
if [[ -n ${protected:-} ]]; then
|
||||||
then
|
if [ $protected == "true" ]; then
|
||||||
if [ $protected == "true" ]
|
|
||||||
then
|
|
||||||
protected=",protected=True"
|
protected=",protected=True"
|
||||||
else
|
else
|
||||||
protected=",protected=False"
|
protected=",protected=False"
|
||||||
|
@ -161,7 +152,7 @@ ynh_permission_create() {
|
||||||
ynh_permission_delete() {
|
ynh_permission_delete() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=permission= )
|
local -A args_array=([p]=permission=)
|
||||||
local permission
|
local permission
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
@ -178,7 +169,7 @@ ynh_permission_delete() {
|
||||||
ynh_permission_exists() {
|
ynh_permission_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=permission= )
|
local -A args_array=([p]=permission=)
|
||||||
local permission
|
local permission
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
@ -201,7 +192,7 @@ ynh_permission_exists() {
|
||||||
ynh_permission_url() {
|
ynh_permission_url() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=puarhc
|
local legacy_args=puarhc
|
||||||
local -A args_array=( [p]=permission= [u]=url= [a]=add_url= [r]=remove_url= [h]=auth_header= [c]=clear_urls )
|
local -A args_array=([p]=permission= [u]=url= [a]=add_url= [r]=remove_url= [h]=auth_header= [c]=clear_urls)
|
||||||
local permission
|
local permission
|
||||||
local url
|
local url
|
||||||
local add_url
|
local add_url
|
||||||
|
@ -215,13 +206,11 @@ ynh_permission_url() {
|
||||||
auth_header=${auth_header:-}
|
auth_header=${auth_header:-}
|
||||||
clear_urls=${clear_urls:-}
|
clear_urls=${clear_urls:-}
|
||||||
|
|
||||||
if [[ -n $url ]]
|
if [[ -n $url ]]; then
|
||||||
then
|
|
||||||
url=",url='$url'"
|
url=",url='$url'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $add_url ]]
|
if [[ -n $add_url ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# For example:
|
# For example:
|
||||||
|
@ -231,8 +220,7 @@ ynh_permission_url() {
|
||||||
add_url=",add_url=['${add_url//;/\',\'}']"
|
add_url=",add_url=['${add_url//;/\',\'}']"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $remove_url ]]
|
if [[ -n $remove_url ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# For example:
|
# For example:
|
||||||
|
@ -242,25 +230,21 @@ ynh_permission_url() {
|
||||||
remove_url=",remove_url=['${remove_url//;/\',\'}']"
|
remove_url=",remove_url=['${remove_url//;/\',\'}']"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $auth_header ]]
|
if [[ -n $auth_header ]]; then
|
||||||
then
|
if [ $auth_header == "true" ]; then
|
||||||
if [ $auth_header == "true" ]
|
|
||||||
then
|
|
||||||
auth_header=",auth_header=True"
|
auth_header=",auth_header=True"
|
||||||
else
|
else
|
||||||
auth_header=",auth_header=False"
|
auth_header=",auth_header=False"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $clear_urls ]] && [ $clear_urls -eq 1 ]
|
if [[ -n $clear_urls ]] && [ $clear_urls -eq 1 ]; then
|
||||||
then
|
|
||||||
clear_urls=",clear_urls=True"
|
clear_urls=",clear_urls=True"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission' $url $add_url $remove_url $auth_header $clear_urls)"
|
yunohost tools shell -c "from yunohost.permission import permission_url; permission_url('$app.$permission' $url $add_url $remove_url $auth_header $clear_urls)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Update a permission for the app
|
# Update a permission for the app
|
||||||
#
|
#
|
||||||
# usage: ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]]
|
# usage: ynh_permission_update --permission "permission" [--add="group" ["group" ...]] [--remove="group" ["group" ...]]
|
||||||
|
@ -276,7 +260,7 @@ ynh_permission_url() {
|
||||||
ynh_permission_update() {
|
ynh_permission_update() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=parltP
|
local legacy_args=parltP
|
||||||
local -A args_array=( [p]=permission= [a]=add= [r]=remove= [l]=label= [t]=show_tile= [P]=protected= )
|
local -A args_array=([p]=permission= [a]=add= [r]=remove= [l]=label= [t]=show_tile= [P]=protected=)
|
||||||
local permission
|
local permission
|
||||||
local add
|
local add
|
||||||
local remove
|
local remove
|
||||||
|
@ -290,8 +274,7 @@ ynh_permission_update() {
|
||||||
show_tile=${show_tile:-}
|
show_tile=${show_tile:-}
|
||||||
protected=${protected:-}
|
protected=${protected:-}
|
||||||
|
|
||||||
if [[ -n $add ]]
|
if [[ -n $add ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# For example:
|
# For example:
|
||||||
|
@ -300,8 +283,7 @@ ynh_permission_update() {
|
||||||
# add=['alice', 'bob']
|
# add=['alice', 'bob']
|
||||||
add=",add=['${add//';'/"','"}']"
|
add=",add=['${add//';'/"','"}']"
|
||||||
fi
|
fi
|
||||||
if [[ -n $remove ]]
|
if [[ -n $remove ]]; then
|
||||||
then
|
|
||||||
# Convert a list from getopts to python list
|
# Convert a list from getopts to python list
|
||||||
# Note that getopts separate the args with ';'
|
# Note that getopts separate the args with ';'
|
||||||
# For example:
|
# For example:
|
||||||
|
@ -311,15 +293,12 @@ ynh_permission_update() {
|
||||||
remove=",remove=['${remove//';'/"','"}']"
|
remove=",remove=['${remove//';'/"','"}']"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $label ]]
|
if [[ -n $label ]]; then
|
||||||
then
|
|
||||||
label=",label='$label'"
|
label=",label='$label'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $show_tile ]]
|
if [[ -n $show_tile ]]; then
|
||||||
then
|
if [ $show_tile == "true" ]; then
|
||||||
if [ $show_tile == "true" ]
|
|
||||||
then
|
|
||||||
show_tile=",show_tile=True"
|
show_tile=",show_tile=True"
|
||||||
else
|
else
|
||||||
show_tile=",show_tile=False"
|
show_tile=",show_tile=False"
|
||||||
|
@ -327,8 +306,7 @@ ynh_permission_update() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n $protected ]]; then
|
if [[ -n $protected ]]; then
|
||||||
if [ $protected == "true" ]
|
if [ $protected == "true" ]; then
|
||||||
then
|
|
||||||
protected=",protected=True"
|
protected=",protected=True"
|
||||||
else
|
else
|
||||||
protected=",protected=False"
|
protected=",protected=False"
|
||||||
|
@ -351,23 +329,20 @@ ynh_permission_update() {
|
||||||
ynh_permission_has_user() {
|
ynh_permission_has_user() {
|
||||||
local legacy_args=pu
|
local legacy_args=pu
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local -A args_array=( [p]=permission= [u]=user= )
|
local -A args_array=([p]=permission= [u]=user=)
|
||||||
local permission
|
local permission
|
||||||
local user
|
local user
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ! ynh_permission_exists --permission=$permission
|
if ! ynh_permission_exists --permission=$permission; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check both allowed and corresponding_users sections in the json
|
# Check both allowed and corresponding_users sections in the json
|
||||||
for section in "allowed" "corresponding_users"
|
for section in "allowed" "corresponding_users"; do
|
||||||
do
|
|
||||||
if yunohost user permission info "$app.$permission" --output-as json --quiet \
|
if yunohost user permission info "$app.$permission" --output-as json --quiet \
|
||||||
| jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null
|
| jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null; then
|
||||||
then
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -381,9 +356,8 @@ ynh_permission_has_user() {
|
||||||
# | exit: Return 1 if the permission doesn't exist, 0 otherwise
|
# | exit: Return 1 if the permission doesn't exist, 0 otherwise
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.2 or higher.
|
# Requires YunoHost version 4.1.2 or higher.
|
||||||
ynh_legacy_permissions_exists () {
|
ynh_legacy_permissions_exists() {
|
||||||
for permission in "skipped" "unprotected" "protected"
|
for permission in "skipped" "unprotected" "protected"; do
|
||||||
do
|
|
||||||
if ynh_permission_exists --permission="legacy_${permission}_uris"; then
|
if ynh_permission_exists --permission="legacy_${permission}_uris"; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
@ -402,9 +376,8 @@ ynh_legacy_permissions_exists () {
|
||||||
# # You can recreate the required permissions here with ynh_permission_create
|
# # You can recreate the required permissions here with ynh_permission_create
|
||||||
# fi
|
# fi
|
||||||
# Requires YunoHost version 4.1.2 or higher.
|
# Requires YunoHost version 4.1.2 or higher.
|
||||||
ynh_legacy_permissions_delete_all () {
|
ynh_legacy_permissions_delete_all() {
|
||||||
for permission in "skipped" "unprotected" "protected"
|
for permission in "skipped" "unprotected" "protected"; do
|
||||||
do
|
|
||||||
if ynh_permission_exists --permission="legacy_${permission}_uris"; then
|
if ynh_permission_exists --permission="legacy_${permission}_uris"; then
|
||||||
ynh_permission_delete --permission="legacy_${permission}_uris"
|
ynh_permission_delete --permission="legacy_${permission}_uris"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -56,10 +56,10 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION}
|
||||||
# children ready to answer.
|
# children ready to answer.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_fpm_config () {
|
ynh_add_fpm_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vtufpd
|
local legacy_args=vtufpd
|
||||||
local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service )
|
local -A args_array=([v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service)
|
||||||
local phpversion
|
local phpversion
|
||||||
local use_template
|
local use_template
|
||||||
local usage
|
local usage
|
||||||
|
@ -86,8 +86,7 @@ ynh_add_fpm_config () {
|
||||||
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
local old_phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
||||||
|
|
||||||
# If the PHP version changed, remove the old fpm conf
|
# If the PHP version changed, remove the old fpm conf
|
||||||
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]
|
if [ -n "$old_phpversion" ] && [ "$old_phpversion" != "$phpversion" ]; then
|
||||||
then
|
|
||||||
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
local old_php_fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
||||||
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
local old_php_finalphpconf="$old_php_fpm_config_dir/pool.d/$app.conf"
|
||||||
|
|
||||||
|
@ -97,25 +96,21 @@ ynh_add_fpm_config () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If the requested PHP version is not the default version for YunoHost
|
# If the requested PHP version is not the default version for YunoHost
|
||||||
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]
|
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]; then
|
||||||
then
|
|
||||||
# If the argument --package is used, add the packages to ynh_install_php to install them from sury
|
# If the argument --package is used, add the packages to ynh_install_php to install them from sury
|
||||||
if [ -n "$package" ]
|
if [ -n "$package" ]; then
|
||||||
then
|
|
||||||
local additionnal_packages="--package=$package"
|
local additionnal_packages="--package=$package"
|
||||||
else
|
else
|
||||||
local additionnal_packages=""
|
local additionnal_packages=""
|
||||||
fi
|
fi
|
||||||
# Install this specific version of PHP.
|
# Install this specific version of PHP.
|
||||||
ynh_install_php --phpversion="$phpversion" "$additionnal_packages"
|
ynh_install_php --phpversion="$phpversion" "$additionnal_packages"
|
||||||
elif [ -n "$package" ]
|
elif [ -n "$package" ]; then
|
||||||
then
|
|
||||||
# Install the additionnal packages from the default repository
|
# Install the additionnal packages from the default repository
|
||||||
ynh_add_app_dependencies --package="$package"
|
ynh_install_app_dependencies "$package"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
then
|
|
||||||
local fpm_service="${app}-phpfpm"
|
local fpm_service="${app}-phpfpm"
|
||||||
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
|
local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm"
|
||||||
else
|
else
|
||||||
|
@ -132,12 +127,10 @@ ynh_add_fpm_config () {
|
||||||
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
|
ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion
|
||||||
|
|
||||||
# Migrate from mutual PHP service to dedicated one.
|
# Migrate from mutual PHP service to dedicated one.
|
||||||
if [ $dedicated_service -eq 1 ]
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
then
|
|
||||||
local old_fpm_config_dir="/etc/php/$phpversion/fpm"
|
local old_fpm_config_dir="/etc/php/$phpversion/fpm"
|
||||||
# If a config file exist in the common pool, move it.
|
# If a config file exist in the common pool, move it.
|
||||||
if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ]
|
if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ]; then
|
||||||
then
|
|
||||||
ynh_print_info --message="Migrate to a dedicated php-fpm service for $app."
|
ynh_print_info --message="Migrate to a dedicated php-fpm service for $app."
|
||||||
# Create a backup of the old file before migration
|
# Create a backup of the old file before migration
|
||||||
ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf"
|
ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf"
|
||||||
|
@ -148,8 +141,7 @@ ynh_add_fpm_config () {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $use_template -eq 1 ]
|
if [ $use_template -eq 1 ]; then
|
||||||
then
|
|
||||||
# Usage 1, use the template in conf/php-fpm.conf
|
# Usage 1, use the template in conf/php-fpm.conf
|
||||||
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
local phpfpm_path="$YNH_APP_BASEDIR/conf/php-fpm.conf"
|
||||||
# Make sure now that the template indeed exists
|
# Make sure now that the template indeed exists
|
||||||
|
@ -181,49 +173,45 @@ pm = __PHP_PM__
|
||||||
pm.max_children = __PHP_MAX_CHILDREN__
|
pm.max_children = __PHP_MAX_CHILDREN__
|
||||||
pm.max_requests = 500
|
pm.max_requests = 500
|
||||||
request_terminate_timeout = 1d
|
request_terminate_timeout = 1d
|
||||||
" > $phpfpm_path
|
" >$phpfpm_path
|
||||||
|
|
||||||
if [ "$php_pm" = "dynamic" ]
|
if [ "$php_pm" = "dynamic" ]; then
|
||||||
then
|
|
||||||
echo "
|
echo "
|
||||||
pm.start_servers = __PHP_START_SERVERS__
|
pm.start_servers = __PHP_START_SERVERS__
|
||||||
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
|
pm.min_spare_servers = __PHP_MIN_SPARE_SERVERS__
|
||||||
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
|
pm.max_spare_servers = __PHP_MAX_SPARE_SERVERS__
|
||||||
" >> $phpfpm_path
|
" >>$phpfpm_path
|
||||||
|
|
||||||
elif [ "$php_pm" = "ondemand" ]
|
elif [ "$php_pm" = "ondemand" ]; then
|
||||||
then
|
|
||||||
echo "
|
echo "
|
||||||
pm.process_idle_timeout = 10s
|
pm.process_idle_timeout = 10s
|
||||||
" >> $phpfpm_path
|
" >>$phpfpm_path
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Concatene the extra config.
|
# Concatene the extra config.
|
||||||
if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then
|
if [ -e $YNH_APP_BASEDIR/conf/extra_php-fpm.conf ]; then
|
||||||
cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >> "$phpfpm_path"
|
cat $YNH_APP_BASEDIR/conf/extra_php-fpm.conf >>"$phpfpm_path"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
|
local finalphpconf="$fpm_config_dir/pool.d/$app.conf"
|
||||||
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
|
ynh_add_config --template="$phpfpm_path" --destination="$finalphpconf"
|
||||||
|
|
||||||
if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]
|
if [ -e "$YNH_APP_BASEDIR/conf/php-fpm.ini" ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead."
|
ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead."
|
||||||
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm.ini" --destination="$fpm_config_dir/conf.d/20-$app.ini"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
then
|
|
||||||
# Create a dedicated php-fpm.conf for the service
|
# Create a dedicated php-fpm.conf for the service
|
||||||
local globalphpconf=$fpm_config_dir/php-fpm-$app.conf
|
local globalphpconf=$fpm_config_dir/php-fpm-$app.conf
|
||||||
|
|
||||||
echo "[global]
|
echo "[global]
|
||||||
pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid
|
pid = /run/php/php__PHPVERSION__-fpm-__APP__.pid
|
||||||
error_log = /var/log/php/fpm-php.__APP__.log
|
error_log = /var/log/php/fpm-php.__APP__.log
|
||||||
syslog.ident = php-fpm-__APP__
|
syslog.ident = php-fpm-__APP__
|
||||||
include = __FINALPHPCONF__
|
include = __FINALPHPCONF__
|
||||||
" > $YNH_APP_BASEDIR/conf/php-fpm-$app.conf
|
" >$YNH_APP_BASEDIR/conf/php-fpm-$app.conf
|
||||||
|
|
||||||
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm-$app.conf" --destination="$globalphpconf"
|
ynh_add_config --template="$YNH_APP_BASEDIR/conf/php-fpm-$app.conf" --destination="$globalphpconf"
|
||||||
|
|
||||||
|
@ -240,7 +228,7 @@ ExecReload=/bin/kill -USR2 \$MAINPID
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
" > $YNH_APP_BASEDIR/conf/$fpm_service
|
" >$YNH_APP_BASEDIR/conf/$fpm_service
|
||||||
|
|
||||||
# Create this dedicated PHP-FPM service
|
# Create this dedicated PHP-FPM service
|
||||||
ynh_add_systemd_config --service=$fpm_service --template=$fpm_service
|
ynh_add_systemd_config --service=$fpm_service --template=$fpm_service
|
||||||
|
@ -252,8 +240,7 @@ WantedBy=multi-user.target
|
||||||
ynh_systemd_action --service_name=$fpm_service --action=restart
|
ynh_systemd_action --service_name=$fpm_service --action=restart
|
||||||
else
|
else
|
||||||
# Validate that the new php conf doesn't break php-fpm entirely
|
# Validate that the new php conf doesn't break php-fpm entirely
|
||||||
if ! php-fpm${phpversion} --test 2>/dev/null
|
if ! php-fpm${phpversion} --test 2>/dev/null; then
|
||||||
then
|
|
||||||
php-fpm${phpversion} --test || true
|
php-fpm${phpversion} --test || true
|
||||||
ynh_secure_remove --file="$finalphpconf"
|
ynh_secure_remove --file="$finalphpconf"
|
||||||
ynh_die --message="The new configuration broke php-fpm?"
|
ynh_die --message="The new configuration broke php-fpm?"
|
||||||
|
@ -267,7 +254,7 @@ WantedBy=multi-user.target
|
||||||
# usage: ynh_remove_fpm_config
|
# usage: ynh_remove_fpm_config
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_remove_fpm_config () {
|
ynh_remove_fpm_config() {
|
||||||
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
||||||
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
|
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
|
||||||
local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service)
|
local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service)
|
||||||
|
@ -279,20 +266,17 @@ ynh_remove_fpm_config () {
|
||||||
phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}"
|
phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}"
|
||||||
|
|
||||||
# Assume default PHP files if not set
|
# Assume default PHP files if not set
|
||||||
if [ -z "$fpm_config_dir" ]
|
if [ -z "$fpm_config_dir" ]; then
|
||||||
then
|
|
||||||
fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm"
|
fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm"
|
||||||
fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm"
|
fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
|
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
|
||||||
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]
|
if [ -e $fpm_config_dir/conf.d/20-$app.ini ]; then
|
||||||
then
|
|
||||||
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
|
ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $dedicated_service -eq 1 ]
|
if [ $dedicated_service -eq 1 ]; then
|
||||||
then
|
|
||||||
# Remove the dedicated service PHP-FPM service for the app
|
# Remove the dedicated service PHP-FPM service for the app
|
||||||
ynh_remove_systemd_config --service=$fpm_service
|
ynh_remove_systemd_config --service=$fpm_service
|
||||||
# Remove the global PHP-FPM conf
|
# Remove the global PHP-FPM conf
|
||||||
|
@ -304,8 +288,7 @@ ynh_remove_fpm_config () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If the PHP version used is not the default version for YunoHost
|
# If the PHP version used is not the default version for YunoHost
|
||||||
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]
|
if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ]; then
|
||||||
then
|
|
||||||
# Remove this specific version of PHP
|
# Remove this specific version of PHP
|
||||||
ynh_remove_php
|
ynh_remove_php
|
||||||
fi
|
fi
|
||||||
|
@ -320,47 +303,22 @@ ynh_remove_fpm_config () {
|
||||||
# | arg: -p, --package= - Additionnal PHP packages to install
|
# | arg: -p, --package= - Additionnal PHP packages to install
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_install_php () {
|
ynh_install_php() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vp
|
local legacy_args=vp
|
||||||
local -A args_array=( [v]=phpversion= [p]=package= )
|
local -A args_array=([v]=phpversion= [p]=package=)
|
||||||
local phpversion
|
local phpversion
|
||||||
local package
|
local package
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
package=${package:-}
|
package=${package:-}
|
||||||
|
|
||||||
# Store phpversion into the config of this app
|
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]; then
|
||||||
ynh_app_setting_set $app phpversion $phpversion
|
|
||||||
|
|
||||||
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]
|
|
||||||
then
|
|
||||||
ynh_die --message="Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
|
ynh_die --message="Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the file if doesn't exist already
|
ynh_install_app_dependencies "$package"
|
||||||
touch /etc/php/ynh_app_version
|
ynh_app_setting_set --app=$app --key=phpversion --value=$specific_php_version
|
||||||
|
|
||||||
# Do not add twice the same line
|
|
||||||
if ! grep --quiet "$YNH_APP_INSTANCE_NAME:" "/etc/php/ynh_app_version"
|
|
||||||
then
|
|
||||||
# Store the ID of this app and the version of PHP requested for it
|
|
||||||
echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add an extra repository for those packages
|
|
||||||
ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version --priority=600
|
|
||||||
|
|
||||||
# Install requested dependencies from this extra repository.
|
|
||||||
# Install PHP-FPM first, otherwise PHP will install apache as a dependency.
|
|
||||||
ynh_add_app_dependencies --package="php${phpversion}-fpm"
|
|
||||||
ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package"
|
|
||||||
|
|
||||||
# Set the default PHP version back as the default version for php-cli.
|
|
||||||
update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION
|
|
||||||
|
|
||||||
# Advertise service in admin panel
|
|
||||||
yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the specific version of PHP used by the app.
|
# Remove the specific version of PHP used by the app.
|
||||||
|
@ -371,35 +329,7 @@ ynh_install_php () {
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.8.1 or higher.
|
# Requires YunoHost version 3.8.1 or higher.
|
||||||
ynh_remove_php () {
|
ynh_remove_php () {
|
||||||
# Get the version of PHP used by this app
|
ynh_remove_app_dependencies
|
||||||
local phpversion=$(ynh_app_setting_get --app=$app --key=phpversion)
|
|
||||||
|
|
||||||
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] || [ -z "$phpversion" ]
|
|
||||||
then
|
|
||||||
if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ]
|
|
||||||
then
|
|
||||||
ynh_print_err "Do not use ynh_remove_php to remove php$YNH_DEFAULT_PHP_VERSION !"
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create the file if doesn't exist already
|
|
||||||
touch /etc/php/ynh_app_version
|
|
||||||
|
|
||||||
# Remove the line for this app
|
|
||||||
sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version"
|
|
||||||
|
|
||||||
# If no other app uses this version of PHP, remove it.
|
|
||||||
if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version"
|
|
||||||
then
|
|
||||||
# Remove the service from the admin panel
|
|
||||||
if ynh_package_is_installed --package="php${phpversion}-fpm"; then
|
|
||||||
yunohost service remove php${phpversion}-fpm
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Purge PHP dependencies for this version.
|
|
||||||
ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Define the values to configure PHP-FPM
|
# Define the values to configure PHP-FPM
|
||||||
|
@ -421,10 +351,10 @@ ynh_remove_php () {
|
||||||
# high - High usage, frequently visited website.
|
# high - High usage, frequently visited website.
|
||||||
#
|
#
|
||||||
# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app)
|
# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app)
|
||||||
ynh_get_scalable_phpfpm () {
|
ynh_get_scalable_phpfpm() {
|
||||||
local legacy_args=ufp
|
local legacy_args=ufp
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local -A args_array=( [u]=usage= [f]=footprint= [p]=print )
|
local -A args_array=([u]=usage= [f]=footprint= [p]=print)
|
||||||
local usage
|
local usage
|
||||||
local footprint
|
local footprint
|
||||||
local print
|
local print
|
||||||
|
@ -435,38 +365,30 @@ ynh_get_scalable_phpfpm () {
|
||||||
usage=${usage,,}
|
usage=${usage,,}
|
||||||
print=${print:-0}
|
print=${print:-0}
|
||||||
|
|
||||||
if [ "$footprint" = "low" ]
|
if [ "$footprint" = "low" ]; then
|
||||||
then
|
|
||||||
footprint=20
|
footprint=20
|
||||||
elif [ "$footprint" = "medium" ]
|
elif [ "$footprint" = "medium" ]; then
|
||||||
then
|
|
||||||
footprint=35
|
footprint=35
|
||||||
elif [ "$footprint" = "high" ]
|
elif [ "$footprint" = "high" ]; then
|
||||||
then
|
|
||||||
footprint=50
|
footprint=50
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Define the factor to determine min_spare_servers
|
# Define the factor to determine min_spare_servers
|
||||||
# to avoid having too few children ready to start for heavy apps
|
# to avoid having too few children ready to start for heavy apps
|
||||||
if [ $footprint -le 20 ]
|
if [ $footprint -le 20 ]; then
|
||||||
then
|
|
||||||
min_spare_servers_factor=8
|
min_spare_servers_factor=8
|
||||||
elif [ $footprint -le 35 ]
|
elif [ $footprint -le 35 ]; then
|
||||||
then
|
|
||||||
min_spare_servers_factor=5
|
min_spare_servers_factor=5
|
||||||
else
|
else
|
||||||
min_spare_servers_factor=3
|
min_spare_servers_factor=3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Define the way the process manager handle child processes.
|
# Define the way the process manager handle child processes.
|
||||||
if [ "$usage" = "low" ]
|
if [ "$usage" = "low" ]; then
|
||||||
then
|
|
||||||
php_pm=ondemand
|
php_pm=ondemand
|
||||||
elif [ "$usage" = "medium" ]
|
elif [ "$usage" = "medium" ]; then
|
||||||
then
|
|
||||||
php_pm=dynamic
|
php_pm=dynamic
|
||||||
elif [ "$usage" = "high" ]
|
elif [ "$usage" = "high" ]; then
|
||||||
then
|
|
||||||
php_pm=static
|
php_pm=static
|
||||||
else
|
else
|
||||||
ynh_die --message="Does not recognize '$usage' as an usage value."
|
ynh_die --message="Does not recognize '$usage' as an usage value."
|
||||||
|
@ -477,8 +399,7 @@ ynh_get_scalable_phpfpm () {
|
||||||
|
|
||||||
at_least_one() {
|
at_least_one() {
|
||||||
# Do not allow value below 1
|
# Do not allow value below 1
|
||||||
if [ $1 -le 0 ]
|
if [ $1 -le 0 ]; then
|
||||||
then
|
|
||||||
echo 1
|
echo 1
|
||||||
else
|
else
|
||||||
echo $1
|
echo $1
|
||||||
|
@ -488,20 +409,18 @@ ynh_get_scalable_phpfpm () {
|
||||||
# Define pm.max_children
|
# Define pm.max_children
|
||||||
# The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app.
|
# The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app.
|
||||||
# So if PHP-FPM start the maximum of children, it won't exceed half of the ram.
|
# So if PHP-FPM start the maximum of children, it won't exceed half of the ram.
|
||||||
php_max_children=$(( $max_ram / 2 / $footprint ))
|
php_max_children=$(($max_ram / 2 / $footprint))
|
||||||
# If process manager is set as static, use half less children.
|
# If process manager is set as static, use half less children.
|
||||||
# Used as static, there's always as many children as the value of pm.max_children
|
# Used as static, there's always as many children as the value of pm.max_children
|
||||||
if [ "$php_pm" = "static" ]
|
if [ "$php_pm" = "static" ]; then
|
||||||
then
|
php_max_children=$(($php_max_children / 2))
|
||||||
php_max_children=$(( $php_max_children / 2 ))
|
|
||||||
fi
|
fi
|
||||||
php_max_children=$(at_least_one $php_max_children)
|
php_max_children=$(at_least_one $php_max_children)
|
||||||
|
|
||||||
# To not overload the proc, limit the number of children to 4 times the number of cores.
|
# To not overload the proc, limit the number of children to 4 times the number of cores.
|
||||||
local core_number=$(nproc)
|
local core_number=$(nproc)
|
||||||
local max_proc=$(( $core_number * 4 ))
|
local max_proc=$(($core_number * 4))
|
||||||
if [ $php_max_children -gt $max_proc ]
|
if [ $php_max_children -gt $max_proc ]; then
|
||||||
then
|
|
||||||
php_max_children=$max_proc
|
php_max_children=$max_proc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -511,16 +430,15 @@ ynh_get_scalable_phpfpm () {
|
||||||
php_max_children=$php_forced_max_children
|
php_max_children=$php_forced_max_children
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$php_pm" = "dynamic" ]
|
if [ "$php_pm" = "dynamic" ]; then
|
||||||
then
|
|
||||||
# Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager
|
# Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager
|
||||||
php_min_spare_servers=$(( $php_max_children / $min_spare_servers_factor ))
|
php_min_spare_servers=$(($php_max_children / $min_spare_servers_factor))
|
||||||
php_min_spare_servers=$(at_least_one $php_min_spare_servers)
|
php_min_spare_servers=$(at_least_one $php_min_spare_servers)
|
||||||
|
|
||||||
php_max_spare_servers=$(( $php_max_children / 2 ))
|
php_max_spare_servers=$(($php_max_children / 2))
|
||||||
php_max_spare_servers=$(at_least_one $php_max_spare_servers)
|
php_max_spare_servers=$(at_least_one $php_max_spare_servers)
|
||||||
|
|
||||||
php_start_servers=$(( $php_min_spare_servers + ( $php_max_spare_servers - $php_min_spare_servers ) /2 ))
|
php_start_servers=$(($php_min_spare_servers + ($php_max_spare_servers - $php_min_spare_servers) / 2))
|
||||||
php_start_servers=$(at_least_one $php_start_servers)
|
php_start_servers=$(at_least_one $php_start_servers)
|
||||||
else
|
else
|
||||||
php_min_spare_servers=0
|
php_min_spare_servers=0
|
||||||
|
@ -528,30 +446,25 @@ ynh_get_scalable_phpfpm () {
|
||||||
php_start_servers=0
|
php_start_servers=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $print -eq 1 ]
|
if [ $print -eq 1 ]; then
|
||||||
then
|
ynh_print_warn --message="Footprint=${footprint}Mb by pool."
|
||||||
ynh_debug --message="Footprint=${footprint}Mb by pool."
|
ynh_print_warn --message="Process manager=$php_pm"
|
||||||
ynh_debug --message="Process manager=$php_pm"
|
ynh_print_warn --message="Max RAM=${max_ram}Mb"
|
||||||
ynh_debug --message="Max RAM=${max_ram}Mb"
|
if [ "$php_pm" != "static" ]; then
|
||||||
if [ "$php_pm" != "static" ]
|
ynh_print_warn --message="\nMax estimated footprint=$(($php_max_children * $footprint))"
|
||||||
then
|
ynh_print_warn --message="Min estimated footprint=$(($php_min_spare_servers * $footprint))"
|
||||||
ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))"
|
|
||||||
ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))"
|
|
||||||
fi
|
fi
|
||||||
if [ "$php_pm" = "dynamic" ]
|
if [ "$php_pm" = "dynamic" ]; then
|
||||||
then
|
ynh_print_warn --message="Estimated average footprint=$(($php_max_spare_servers * $footprint))"
|
||||||
ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))"
|
elif [ "$php_pm" = "static" ]; then
|
||||||
elif [ "$php_pm" = "static" ]
|
ynh_print_warn --message="Estimated footprint=$(($php_max_children * $footprint))"
|
||||||
then
|
|
||||||
ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))"
|
|
||||||
fi
|
fi
|
||||||
ynh_debug --message="\nRaw php-fpm values:"
|
ynh_print_warn --message="\nRaw php-fpm values:"
|
||||||
ynh_debug --message="pm.max_children = $php_max_children"
|
ynh_print_warn --message="pm.max_children = $php_max_children"
|
||||||
if [ "$php_pm" = "dynamic" ]
|
if [ "$php_pm" = "dynamic" ]; then
|
||||||
then
|
ynh_print_warn --message="pm.start_servers = $php_start_servers"
|
||||||
ynh_debug --message="pm.start_servers = $php_start_servers"
|
ynh_print_warn --message="pm.min_spare_servers = $php_min_spare_servers"
|
||||||
ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers"
|
ynh_print_warn --message="pm.max_spare_servers = $php_max_spare_servers"
|
||||||
ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -569,10 +482,10 @@ YNH_COMPOSER_VERSION=${YNH_COMPOSER_VERSION:-$YNH_DEFAULT_COMPOSER_VERSION}
|
||||||
# | arg: -c, --commands - Commands to execute.
|
# | arg: -c, --commands - Commands to execute.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.2 or higher.
|
# Requires YunoHost version 4.2 or higher.
|
||||||
ynh_composer_exec () {
|
ynh_composer_exec() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vwc
|
local legacy_args=vwc
|
||||||
declare -Ar args_array=( [v]=phpversion= [w]=workdir= [c]=commands= )
|
declare -Ar args_array=([v]=phpversion= [w]=workdir= [c]=commands=)
|
||||||
local phpversion
|
local phpversion
|
||||||
local workdir
|
local workdir
|
||||||
local commands
|
local commands
|
||||||
|
@ -595,10 +508,10 @@ ynh_composer_exec () {
|
||||||
# | arg: -c, --composerversion - Composer version to install
|
# | arg: -c, --composerversion - Composer version to install
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.2 or higher.
|
# Requires YunoHost version 4.2 or higher.
|
||||||
ynh_install_composer () {
|
ynh_install_composer() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=vwac
|
local legacy_args=vwac
|
||||||
declare -Ar args_array=( [v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
|
declare -Ar args_array=([v]=phpversion= [w]=workdir= [a]=install_args= [c]=composerversion=)
|
||||||
local phpversion
|
local phpversion
|
||||||
local workdir
|
local workdir
|
||||||
local install_args
|
local install_args
|
||||||
|
|
|
@ -46,8 +46,7 @@ ynh_psql_execute_as_root() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
database="${database:-}"
|
database="${database:-}"
|
||||||
|
|
||||||
if [ -n "$database" ]
|
if [ -n "$database" ]; then
|
||||||
then
|
|
||||||
database="--database=$database"
|
database="--database=$database"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -72,8 +71,7 @@ ynh_psql_execute_file_as_root() {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
database="${database:-}"
|
database="${database:-}"
|
||||||
|
|
||||||
if [ -n "$database" ]
|
if [ -n "$database" ]; then
|
||||||
then
|
|
||||||
database="--database=$database"
|
database="--database=$database"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -175,8 +173,7 @@ ynh_psql_user_exists() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user"
|
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user"; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -198,8 +195,7 @@ ynh_psql_database_exists() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"
|
if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then
|
||||||
then
|
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
|
@ -269,16 +265,14 @@ ynh_psql_remove_db() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_psql_database_exists --database=$db_name
|
if ynh_psql_database_exists --database=$db_name; then # Check if the database exists
|
||||||
then # Check if the database exists
|
|
||||||
ynh_psql_drop_db $db_name # Remove the database
|
ynh_psql_drop_db $db_name # Remove the database
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="Database $db_name not found"
|
ynh_print_warn --message="Database $db_name not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove psql user if it exists
|
# Remove psql user if it exists
|
||||||
if ynh_psql_user_exists --user=$db_user
|
if ynh_psql_user_exists --user=$db_user; then
|
||||||
then
|
|
||||||
ynh_psql_drop_user $db_user
|
ynh_psql_drop_user $db_user
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="User $db_user not found"
|
ynh_print_warn --message="User $db_user not found"
|
||||||
|
@ -310,8 +304,7 @@ ynh_psql_test_if_first_run() {
|
||||||
|
|
||||||
# If this is the very first time, we define the root password
|
# If this is the very first time, we define the root password
|
||||||
# and configure a few things
|
# and configure a few things
|
||||||
if [ ! -f "$PSQL_ROOT_PWD_FILE" ]
|
if [ ! -f "$PSQL_ROOT_PWD_FILE" ]; then
|
||||||
then
|
|
||||||
local pg_hba=/etc/postgresql/$PSQL_VERSION/main/pg_hba.conf
|
local pg_hba=/etc/postgresql/$PSQL_VERSION/main/pg_hba.conf
|
||||||
|
|
||||||
local psql_root_password="$(ynh_string_random)"
|
local psql_root_password="$(ynh_string_random)"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
ynh_app_setting_get() {
|
ynh_app_setting_get() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ak
|
local legacy_args=ak
|
||||||
local -A args_array=( [a]=app= [k]=key= )
|
local -A args_array=([a]=app= [k]=key=)
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -34,7 +34,7 @@ ynh_app_setting_get() {
|
||||||
ynh_app_setting_set() {
|
ynh_app_setting_set() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=akv
|
local legacy_args=akv
|
||||||
local -A args_array=( [a]=app= [k]=key= [v]=value= )
|
local -A args_array=([a]=app= [k]=key= [v]=value=)
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
local value
|
local value
|
||||||
|
@ -58,7 +58,7 @@ ynh_app_setting_set() {
|
||||||
ynh_app_setting_delete() {
|
ynh_app_setting_delete() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ak
|
local legacy_args=ak
|
||||||
local -A args_array=( [a]=app= [k]=key= )
|
local -A args_array=([a]=app= [k]=key=)
|
||||||
local app
|
local app
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -76,8 +76,7 @@ ynh_app_setting_delete() {
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
ynh_app_setting()
|
ynh_app_setting() {
|
||||||
{
|
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python3 - <<EOF
|
ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python3 - <<EOF
|
||||||
import os, yaml, sys
|
import os, yaml, sys
|
||||||
|
@ -115,10 +114,10 @@ EOF
|
||||||
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
|
# example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_webpath_available () {
|
ynh_webpath_available() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=dp
|
local legacy_args=dp
|
||||||
local -A args_array=( [d]=domain= [p]=path_url= )
|
local -A args_array=([d]=domain= [p]=path_url=)
|
||||||
local domain
|
local domain
|
||||||
local path_url
|
local path_url
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -137,10 +136,10 @@ ynh_webpath_available () {
|
||||||
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
|
# example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_webpath_register () {
|
ynh_webpath_register() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=adp
|
local legacy_args=adp
|
||||||
local -A args_array=( [a]=app= [d]=domain= [p]=path_url= )
|
local -A args_array=([a]=app= [d]=domain= [p]=path_url=)
|
||||||
local app
|
local app
|
||||||
local domain
|
local domain
|
||||||
local path_url
|
local path_url
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
ynh_string_random() {
|
ynh_string_random() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=l
|
local legacy_args=l
|
||||||
local -A args_array=( [l]=length= )
|
local -A args_array=([l]=length=)
|
||||||
local length
|
local length
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
length=${length:-24}
|
length=${length:-24}
|
||||||
|
|
||||||
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \
|
dd if=/dev/urandom bs=1 count=1000 2>/dev/null \
|
||||||
| tr --complement --delete 'A-Za-z0-9' \
|
| tr --complement --delete 'A-Za-z0-9' \
|
||||||
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
|
| sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p'
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,10 @@ ynh_string_random() {
|
||||||
# sub-expressions can be used (see sed manual page for more information)
|
# sub-expressions can be used (see sed manual page for more information)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_replace_string () {
|
ynh_replace_string() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mrf
|
local legacy_args=mrf
|
||||||
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
local -A args_array=([m]=match_string= [r]=replace_string= [f]=target_file=)
|
||||||
local match_string
|
local match_string
|
||||||
local replace_string
|
local replace_string
|
||||||
local target_file
|
local target_file
|
||||||
|
@ -65,10 +65,10 @@ ynh_replace_string () {
|
||||||
# characters, you can't use some regular expressions and sub-expressions.
|
# characters, you can't use some regular expressions and sub-expressions.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.7 or higher.
|
# Requires YunoHost version 2.7.7 or higher.
|
||||||
ynh_replace_special_string () {
|
ynh_replace_special_string() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mrf
|
local legacy_args=mrf
|
||||||
local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
|
local -A args_array=([m]=match_string= [r]=replace_string= [f]=target_file=)
|
||||||
local match_string
|
local match_string
|
||||||
local replace_string
|
local replace_string
|
||||||
local target_file
|
local target_file
|
||||||
|
@ -97,10 +97,10 @@ ynh_replace_special_string () {
|
||||||
# Underscorify the string (replace - and . by _)
|
# Underscorify the string (replace - and . by _)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.2.4 or higher.
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_sanitize_dbid () {
|
ynh_sanitize_dbid() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=n
|
local legacy_args=n
|
||||||
local -A args_array=( [n]=db_name= )
|
local -A args_array=([n]=db_name=)
|
||||||
local db_name
|
local db_name
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -127,10 +127,10 @@ ynh_sanitize_dbid () {
|
||||||
# | arg: -p, --path_url= - URL path to normalize before using it
|
# | arg: -p, --path_url= - URL path to normalize before using it
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_normalize_url_path () {
|
ynh_normalize_url_path() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
local -A args_array=( [p]=path_url= )
|
local -A args_array=([p]=path_url=)
|
||||||
local path_url
|
local path_url
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
# format and how placeholders are replaced with actual variables.
|
# format and how placeholders are replaced with actual variables.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_systemd_config () {
|
ynh_add_systemd_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=stv
|
local legacy_args=stv
|
||||||
local -A args_array=( [s]=service= [t]=template= [v]=others_var=)
|
local -A args_array=([s]=service= [t]=template= [v]=others_var=)
|
||||||
local service
|
local service
|
||||||
local template
|
local template
|
||||||
local others_var
|
local others_var
|
||||||
|
@ -39,18 +39,17 @@ ynh_add_systemd_config () {
|
||||||
# | arg: -s, --service= - Service name (optionnal, $app by default)
|
# | arg: -s, --service= - Service name (optionnal, $app by default)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.2 or higher.
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_remove_systemd_config () {
|
ynh_remove_systemd_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=s
|
local legacy_args=s
|
||||||
local -A args_array=( [s]=service= )
|
local -A args_array=([s]=service=)
|
||||||
local service
|
local service
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
local service="${service:-$app}"
|
local service="${service:-$app}"
|
||||||
|
|
||||||
local finalsystemdconf="/etc/systemd/system/$service.service"
|
local finalsystemdconf="/etc/systemd/system/$service.service"
|
||||||
if [ -e "$finalsystemdconf" ]
|
if [ -e "$finalsystemdconf" ]; then
|
||||||
then
|
|
||||||
ynh_systemd_action --service_name=$service --action=stop
|
ynh_systemd_action --service_name=$service --action=stop
|
||||||
systemctl disable $service --quiet
|
systemctl disable $service --quiet
|
||||||
ynh_secure_remove --file="$finalsystemdconf"
|
ynh_secure_remove --file="$finalsystemdconf"
|
||||||
|
@ -72,7 +71,7 @@ ynh_remove_systemd_config () {
|
||||||
ynh_systemd_action() {
|
ynh_systemd_action() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=nalpte
|
local legacy_args=nalpte
|
||||||
local -A args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
|
local -A args_array=([n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length=)
|
||||||
local service_name
|
local service_name
|
||||||
local action
|
local action
|
||||||
local line_match
|
local line_match
|
||||||
|
@ -89,25 +88,22 @@ ynh_systemd_action() {
|
||||||
timeout=${timeout:-300}
|
timeout=${timeout:-300}
|
||||||
|
|
||||||
# Manage case of service already stopped
|
# Manage case of service already stopped
|
||||||
if [ "$action" == "stop" ] && ! systemctl is-active --quiet $service_name
|
if [ "$action" == "stop" ] && ! systemctl is-active --quiet $service_name; then
|
||||||
then
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Start to read the log
|
# Start to read the log
|
||||||
if [[ -n "$line_match" ]]
|
if [[ -n "$line_match" ]]; then
|
||||||
then
|
|
||||||
local templog="$(mktemp)"
|
local templog="$(mktemp)"
|
||||||
# Following the starting of the app in its log
|
# Following the starting of the app in its log
|
||||||
if [ "$log_path" == "systemd" ]
|
if [ "$log_path" == "systemd" ]; then
|
||||||
then
|
|
||||||
# Read the systemd journal
|
# Read the systemd journal
|
||||||
journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" &
|
journalctl --unit=$service_name --follow --since=-0 --quiet >"$templog" &
|
||||||
# Get the PID of the journalctl command
|
# Get the PID of the journalctl command
|
||||||
local pid_tail=$!
|
local pid_tail=$!
|
||||||
else
|
else
|
||||||
# Read the specified log file
|
# Read the specified log file
|
||||||
tail --follow=name --retry --lines=0 "$log_path" > "$templog" 2>&1 &
|
tail --follow=name --retry --lines=0 "$log_path" >"$templog" 2>&1 &
|
||||||
# Get the PID of the tail command
|
# Get the PID of the tail command
|
||||||
local pid_tail=$!
|
local pid_tail=$!
|
||||||
fi
|
fi
|
||||||
|
@ -119,13 +115,11 @@ ynh_systemd_action() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If the service fails to perform the action
|
# If the service fails to perform the action
|
||||||
if ! systemctl $action $service_name
|
if ! systemctl $action $service_name; then
|
||||||
then
|
|
||||||
# Show syslog for this service
|
# Show syslog for this service
|
||||||
ynh_exec_err journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
|
ynh_exec_err journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
|
||||||
# If a log is specified for this service, show also the content of this log
|
# If a log is specified for this service, show also the content of this log
|
||||||
if [ -e "$log_path" ]
|
if [ -e "$log_path" ]; then
|
||||||
then
|
|
||||||
ynh_exec_err tail --lines=$length "$log_path"
|
ynh_exec_err tail --lines=$length "$log_path"
|
||||||
fi
|
fi
|
||||||
ynh_clean_check_starting
|
ynh_clean_check_starting
|
||||||
|
@ -133,15 +127,12 @@ ynh_systemd_action() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Start the timeout and try to find line_match
|
# Start the timeout and try to find line_match
|
||||||
if [[ -n "${line_match:-}" ]]
|
if [[ -n "${line_match:-}" ]]; then
|
||||||
then
|
|
||||||
set +x
|
set +x
|
||||||
local i=0
|
local i=0
|
||||||
for i in $(seq 1 $timeout)
|
for i in $(seq 1 $timeout); do
|
||||||
do
|
|
||||||
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
|
# Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
|
||||||
if grep --extended-regexp --quiet "$line_match" "$templog"
|
if grep --extended-regexp --quiet "$line_match" "$templog"; then
|
||||||
then
|
|
||||||
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
ynh_print_info --message="The service $service_name has correctly executed the action ${action}."
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
|
@ -154,13 +145,11 @@ ynh_systemd_action() {
|
||||||
if [ $i -ge 3 ]; then
|
if [ $i -ge 3 ]; then
|
||||||
echo "" >&2
|
echo "" >&2
|
||||||
fi
|
fi
|
||||||
if [ $i -eq $timeout ]
|
if [ $i -eq $timeout ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout."
|
ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout."
|
||||||
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
|
ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:"
|
||||||
ynh_exec_warn journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
|
ynh_exec_warn journalctl --quiet --no-hostname --no-pager --lines=$length --unit=$service_name
|
||||||
if [ -e "$log_path" ]
|
if [ -e "$log_path" ]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="\-\-\-"
|
ynh_print_warn --message="\-\-\-"
|
||||||
ynh_exec_warn tail --lines=$length "$log_path"
|
ynh_exec_warn tail --lines=$length "$log_path"
|
||||||
fi
|
fi
|
||||||
|
@ -174,14 +163,12 @@ ynh_systemd_action() {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_clean_check_starting () {
|
ynh_clean_check_starting() {
|
||||||
if [ -n "${pid_tail:-}" ]
|
if [ -n "${pid_tail:-}" ]; then
|
||||||
then
|
|
||||||
# Stop the execution of tail.
|
# Stop the execution of tail.
|
||||||
kill -SIGTERM $pid_tail 2>&1
|
kill -SIGTERM $pid_tail 2>&1
|
||||||
fi
|
fi
|
||||||
if [ -n "${templog:-}" ]
|
if [ -n "${templog:-}" ]; then
|
||||||
then
|
|
||||||
ynh_secure_remove --file="$templog" 2>&1
|
ynh_secure_remove --file="$templog" 2>&1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
ynh_user_exists() {
|
ynh_user_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
local -A args_array=( [u]=username= )
|
local -A args_array=([u]=username=)
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -33,7 +33,7 @@ ynh_user_exists() {
|
||||||
ynh_user_get_info() {
|
ynh_user_get_info() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uk
|
local legacy_args=uk
|
||||||
local -A args_array=( [u]=username= [k]=key= )
|
local -A args_array=([u]=username= [k]=key=)
|
||||||
local username
|
local username
|
||||||
local key
|
local key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -64,7 +64,7 @@ ynh_user_list() {
|
||||||
ynh_system_user_exists() {
|
ynh_system_user_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
local -A args_array=( [u]=username= )
|
local -A args_array=([u]=username=)
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -82,7 +82,7 @@ ynh_system_user_exists() {
|
||||||
ynh_system_group_exists() {
|
ynh_system_group_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=g
|
local legacy_args=g
|
||||||
local -A args_array=( [g]=group= )
|
local -A args_array=([g]=group=)
|
||||||
local group
|
local group
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -108,10 +108,10 @@ ynh_system_group_exists() {
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_system_user_create () {
|
ynh_system_user_create() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uhs
|
local legacy_args=uhs
|
||||||
local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell [g]=groups= )
|
local -A args_array=([u]=username= [h]=home_dir= [s]=use_shell [g]=groups=)
|
||||||
local username
|
local username
|
||||||
local home_dir
|
local home_dir
|
||||||
local use_shell
|
local use_shell
|
||||||
|
@ -123,16 +123,14 @@ ynh_system_user_create () {
|
||||||
home_dir="${home_dir:-}"
|
home_dir="${home_dir:-}"
|
||||||
groups="${groups:-}"
|
groups="${groups:-}"
|
||||||
|
|
||||||
if ! ynh_system_user_exists "$username" # Check if the user exists on the system
|
if ! ynh_system_user_exists "$username"; then # Check if the user exists on the system
|
||||||
then # If the user doesn't exist
|
# If the user doesn't exist
|
||||||
if [ -n "$home_dir" ]
|
if [ -n "$home_dir" ]; then # If a home dir is mentioned
|
||||||
then # If a home dir is mentioned
|
|
||||||
local user_home_dir="--home-dir $home_dir"
|
local user_home_dir="--home-dir $home_dir"
|
||||||
else
|
else
|
||||||
local user_home_dir="--no-create-home"
|
local user_home_dir="--no-create-home"
|
||||||
fi
|
fi
|
||||||
if [ $use_shell -eq 1 ]
|
if [ $use_shell -eq 1 ]; then # If we want a shell for the user
|
||||||
then # If we want a shell for the user
|
|
||||||
local shell="" # Use default shell
|
local shell="" # Use default shell
|
||||||
else
|
else
|
||||||
local shell="--shell /usr/sbin/nologin"
|
local shell="--shell /usr/sbin/nologin"
|
||||||
|
@ -141,8 +139,7 @@ ynh_system_user_create () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local group
|
local group
|
||||||
for group in $groups
|
for group in $groups; do
|
||||||
do
|
|
||||||
usermod -a -G "$group" "$username"
|
usermod -a -G "$group" "$username"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -153,25 +150,23 @@ ynh_system_user_create () {
|
||||||
# | arg: -u, --username= - Name of the system user that will be create
|
# | arg: -u, --username= - Name of the system user that will be create
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_system_user_delete () {
|
ynh_system_user_delete() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
local -A args_array=( [u]=username= )
|
local -A args_array=([u]=username=)
|
||||||
local username
|
local username
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# Check if the user exists on the system
|
# Check if the user exists on the system
|
||||||
if ynh_system_user_exists "$username"
|
if ynh_system_user_exists "$username"; then
|
||||||
then
|
|
||||||
deluser $username
|
deluser $username
|
||||||
else
|
else
|
||||||
ynh_print_warn --message="The user $username was not found"
|
ynh_print_warn --message="The user $username was not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if the group exists on the system
|
# Check if the group exists on the system
|
||||||
if ynh_system_group_exists "$username"
|
if ynh_system_group_exists "$username"; then
|
||||||
then
|
|
||||||
delgroup $username
|
delgroup $username
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ YNH_APP_BASEDIR=${YNH_APP_BASEDIR:-$(realpath ..)}
|
||||||
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
|
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_exit_properly () {
|
ynh_exit_properly() {
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
|
|
||||||
rm -rf "/var/cache/yunohost/download/"
|
rm -rf "/var/cache/yunohost/download/"
|
||||||
|
@ -36,7 +36,7 @@ ynh_exit_properly () {
|
||||||
# Small tempo to avoid the next message being mixed up with other DEBUG messages
|
# Small tempo to avoid the next message being mixed up with other DEBUG messages
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
|
|
||||||
if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script.
|
if type -t ynh_clean_setup >/dev/null; then # Check if the function exist in the app script.
|
||||||
ynh_clean_setup # Call the function to do specific cleaning for the app.
|
ynh_clean_setup # Call the function to do specific cleaning for the app.
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ ynh_exit_properly () {
|
||||||
# and a call to `ynh_clean_setup` is triggered if it has been defined by your script.
|
# and a call to `ynh_clean_setup` is triggered if it has been defined by your script.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_abort_if_errors () {
|
ynh_abort_if_errors() {
|
||||||
set -o errexit # set -e; Exit if a command fail
|
set -o errexit # set -e; Exit if a command fail
|
||||||
set -o nounset # set -u; And if a variable is used unset
|
set -o nounset # set -u; And if a variable is used unset
|
||||||
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
||||||
|
@ -99,10 +99,10 @@ ynh_abort_if_errors () {
|
||||||
# - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir
|
# - Extra files in `sources/extra_files/$src_id` will be copied to dest_dir
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_setup_source () {
|
ynh_setup_source() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=dsk
|
local legacy_args=dsk
|
||||||
local -A args_array=( [d]=dest_dir= [s]=source_id= [k]=keep= )
|
local -A args_array=([d]=dest_dir= [s]=source_id= [k]=keep=)
|
||||||
local dest_dir
|
local dest_dir
|
||||||
local source_id
|
local source_id
|
||||||
local keep
|
local keep
|
||||||
|
@ -133,15 +133,13 @@ ynh_setup_source () {
|
||||||
src_filename="${source_id}.${src_format}"
|
src_filename="${source_id}.${src_format}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
|
# (Unused?) mecanism where one can have the file in a special local cache to not have to download it...
|
||||||
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}"
|
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}"
|
||||||
|
|
||||||
mkdir -p /var/cache/yunohost/download/${YNH_APP_ID}/
|
mkdir -p /var/cache/yunohost/download/${YNH_APP_ID}/
|
||||||
src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${src_filename}"
|
src_filename="/var/cache/yunohost/download/${YNH_APP_ID}/${src_filename}"
|
||||||
|
|
||||||
if test -e "$local_src"
|
if test -e "$local_src"; then
|
||||||
then
|
|
||||||
cp $local_src $src_filename
|
cp $local_src $src_filename
|
||||||
else
|
else
|
||||||
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
[ -n "$src_url" ] || ynh_die "Couldn't parse SOURCE_URL from $src_file_path ?"
|
||||||
|
@ -162,15 +160,12 @@ ynh_setup_source () {
|
||||||
# Keep files to be backup/restored at the end of the helper
|
# Keep files to be backup/restored at the end of the helper
|
||||||
# Assuming $dest_dir already exists
|
# Assuming $dest_dir already exists
|
||||||
rm -rf /var/cache/yunohost/files_to_keep_during_setup_source/
|
rm -rf /var/cache/yunohost/files_to_keep_during_setup_source/
|
||||||
if [ -n "$keep" ] && [ -e "$dest_dir" ]
|
if [ -n "$keep" ] && [ -e "$dest_dir" ]; then
|
||||||
then
|
|
||||||
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
||||||
mkdir -p $keep_dir
|
mkdir -p $keep_dir
|
||||||
local stuff_to_keep
|
local stuff_to_keep
|
||||||
for stuff_to_keep in $keep
|
for stuff_to_keep in $keep; do
|
||||||
do
|
if [ -e "$dest_dir/$stuff_to_keep" ]; then
|
||||||
if [ -e "$dest_dir/$stuff_to_keep" ]
|
|
||||||
then
|
|
||||||
mkdir --parents "$(dirname "$keep_dir/$stuff_to_keep")"
|
mkdir --parents "$(dirname "$keep_dir/$stuff_to_keep")"
|
||||||
cp --archive "$dest_dir/$stuff_to_keep" "$keep_dir/$stuff_to_keep"
|
cp --archive "$dest_dir/$stuff_to_keep" "$keep_dir/$stuff_to_keep"
|
||||||
fi
|
fi
|
||||||
|
@ -180,20 +175,16 @@ ynh_setup_source () {
|
||||||
# Extract source into the app dir
|
# Extract source into the app dir
|
||||||
mkdir --parents "$dest_dir"
|
mkdir --parents "$dest_dir"
|
||||||
|
|
||||||
if [ -n "${final_path:-}" ] && [ "$dest_dir" == "$final_path" ]
|
if [ -n "${final_path:-}" ] && [ "$dest_dir" == "$final_path" ]; then
|
||||||
then
|
|
||||||
_ynh_apply_default_permissions $dest_dir
|
_ynh_apply_default_permissions $dest_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! "$src_extract"
|
if ! "$src_extract"; then
|
||||||
then
|
|
||||||
mv $src_filename $dest_dir
|
mv $src_filename $dest_dir
|
||||||
elif [ "$src_format" = "zip" ]
|
elif [ "$src_format" = "zip" ]; then
|
||||||
then
|
|
||||||
# Zip format
|
# Zip format
|
||||||
# Using of a temp directory, because unzip doesn't manage --strip-components
|
# Using of a temp directory, because unzip doesn't manage --strip-components
|
||||||
if $src_in_subdir
|
if $src_in_subdir; then
|
||||||
then
|
|
||||||
local tmp_dir=$(mktemp --directory)
|
local tmp_dir=$(mktemp --directory)
|
||||||
unzip -quo $src_filename -d "$tmp_dir"
|
unzip -quo $src_filename -d "$tmp_dir"
|
||||||
cp --archive $tmp_dir/*/. "$dest_dir"
|
cp --archive $tmp_dir/*/. "$dest_dir"
|
||||||
|
@ -204,18 +195,15 @@ ynh_setup_source () {
|
||||||
ynh_secure_remove --file="$src_filename"
|
ynh_secure_remove --file="$src_filename"
|
||||||
else
|
else
|
||||||
local strip=""
|
local strip=""
|
||||||
if [ "$src_in_subdir" != "false" ]
|
if [ "$src_in_subdir" != "false" ]; then
|
||||||
then
|
if [ "$src_in_subdir" == "true" ]; then
|
||||||
if [ "$src_in_subdir" == "true" ]
|
|
||||||
then
|
|
||||||
local sub_dirs=1
|
local sub_dirs=1
|
||||||
else
|
else
|
||||||
local sub_dirs="$src_in_subdir"
|
local sub_dirs="$src_in_subdir"
|
||||||
fi
|
fi
|
||||||
strip="--strip-components $sub_dirs"
|
strip="--strip-components $sub_dirs"
|
||||||
fi
|
fi
|
||||||
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]]
|
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]]; then
|
||||||
then
|
|
||||||
tar --extract --file=$src_filename --directory="$dest_dir" $strip
|
tar --extract --file=$src_filename --directory="$dest_dir" $strip
|
||||||
else
|
else
|
||||||
ynh_die --message="Archive format unrecognized."
|
ynh_die --message="Archive format unrecognized."
|
||||||
|
@ -224,17 +212,16 @@ ynh_setup_source () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Apply patches
|
# Apply patches
|
||||||
if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]
|
if [ -d "$YNH_APP_BASEDIR/sources/patches/" ]; then
|
||||||
then
|
|
||||||
local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/)
|
local patches_folder=$(realpath $YNH_APP_BASEDIR/sources/patches/)
|
||||||
if (( $(find $patches_folder -type f -name "${source_id}-*.patch" 2> /dev/null | wc --lines) > "0" ))
|
if (($(find $patches_folder -type f -name "${source_id}-*.patch" 2>/dev/null | wc --lines) > "0")); then
|
||||||
then
|
(
|
||||||
(cd "$dest_dir"
|
cd "$dest_dir"
|
||||||
for p in $patches_folder/${source_id}-*.patch
|
for p in $patches_folder/${source_id}-*.patch; do
|
||||||
do
|
|
||||||
echo $p
|
echo $p
|
||||||
patch --strip=1 < $p
|
patch --strip=1 <$p
|
||||||
done) || ynh_die --message="Unable to apply patches"
|
done
|
||||||
|
) || ynh_die --message="Unable to apply patches"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -245,14 +232,11 @@ ynh_setup_source () {
|
||||||
|
|
||||||
# Keep files to be backup/restored at the end of the helper
|
# Keep files to be backup/restored at the end of the helper
|
||||||
# Assuming $dest_dir already exists
|
# Assuming $dest_dir already exists
|
||||||
if [ -n "$keep" ]
|
if [ -n "$keep" ]; then
|
||||||
then
|
|
||||||
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
local keep_dir=/var/cache/yunohost/files_to_keep_during_setup_source/${YNH_APP_ID}
|
||||||
local stuff_to_keep
|
local stuff_to_keep
|
||||||
for stuff_to_keep in $keep
|
for stuff_to_keep in $keep; do
|
||||||
do
|
if [ -e "$keep_dir/$stuff_to_keep" ]; then
|
||||||
if [ -e "$keep_dir/$stuff_to_keep" ]
|
|
||||||
then
|
|
||||||
mkdir --parents "$(dirname "$dest_dir/$stuff_to_keep")"
|
mkdir --parents "$(dirname "$dest_dir/$stuff_to_keep")"
|
||||||
cp --archive "$keep_dir/$stuff_to_keep" "$dest_dir/$stuff_to_keep"
|
cp --archive "$keep_dir/$stuff_to_keep" "$dest_dir/$stuff_to_keep"
|
||||||
fi
|
fi
|
||||||
|
@ -276,7 +260,7 @@ ynh_setup_source () {
|
||||||
# `$domain` and `$path_url` should be defined externally (and correspond to the domain.tld and the /path (of the app?))
|
# `$domain` and `$path_url` should be defined externally (and correspond to the domain.tld and the /path (of the app?))
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_local_curl () {
|
ynh_local_curl() {
|
||||||
# Define url of page to curl
|
# Define url of page to curl
|
||||||
local local_page=$(ynh_normalize_url_path $1)
|
local local_page=$(ynh_normalize_url_path $1)
|
||||||
local full_path=$path_url$local_page
|
local full_path=$path_url$local_page
|
||||||
|
@ -290,12 +274,10 @@ ynh_local_curl () {
|
||||||
# Concatenate all other arguments with '&' to prepare POST data
|
# Concatenate all other arguments with '&' to prepare POST data
|
||||||
local POST_data=""
|
local POST_data=""
|
||||||
local arg=""
|
local arg=""
|
||||||
for arg in "${@:2}"
|
for arg in "${@:2}"; do
|
||||||
do
|
|
||||||
POST_data="${POST_data}${arg}&"
|
POST_data="${POST_data}${arg}&"
|
||||||
done
|
done
|
||||||
if [ -n "$POST_data" ]
|
if [ -n "$POST_data" ]; then
|
||||||
then
|
|
||||||
# Add --data arg and remove the last character, which is an unecessary '&'
|
# Add --data arg and remove the last character, which is an unecessary '&'
|
||||||
POST_data="--data ${POST_data::-1}"
|
POST_data="--data ${POST_data::-1}"
|
||||||
fi
|
fi
|
||||||
|
@ -353,10 +335,10 @@ ynh_local_curl () {
|
||||||
# into the app settings when configuration is done.
|
# into the app settings when configuration is done.
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_add_config () {
|
ynh_add_config() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=tdv
|
local legacy_args=tdv
|
||||||
local -A args_array=( [t]=template= [d]=destination= )
|
local -A args_array=([t]=template= [d]=destination=)
|
||||||
local template
|
local template
|
||||||
local destination
|
local destination
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -414,17 +396,16 @@ ynh_add_config () {
|
||||||
# __VAR_2__ by $var_2
|
# __VAR_2__ by $var_2
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 4.1.0 or higher.
|
# Requires YunoHost version 4.1.0 or higher.
|
||||||
ynh_replace_vars () {
|
ynh_replace_vars() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
local -A args_array=( [f]=file= )
|
local -A args_array=([f]=file=)
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# Replace specific YunoHost variables
|
# Replace specific YunoHost variables
|
||||||
if test -n "${path_url:-}"
|
if test -n "${path_url:-}"; then
|
||||||
then
|
|
||||||
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
|
# path_url_slash_less is path_url, or a blank value if path_url is only '/'
|
||||||
local path_url_slash_less=${path_url%/}
|
local path_url_slash_less=${path_url%/}
|
||||||
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$file"
|
ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$file"
|
||||||
|
@ -448,12 +429,11 @@ ynh_replace_vars () {
|
||||||
# Replace others variables
|
# Replace others variables
|
||||||
|
|
||||||
# List other unique (__ __) variables in $file
|
# List other unique (__ __) variables in $file
|
||||||
local uniques_vars=( $(grep -oP '__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__' $file | sort --unique | sed "s@__\([^.]*\)__@\L\1@g" ))
|
local uniques_vars=($(grep -oP '__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__' $file | sort --unique | sed "s@__\([^.]*\)__@\L\1@g"))
|
||||||
|
|
||||||
# Do the replacement
|
# Do the replacement
|
||||||
local delimit=@
|
local delimit=@
|
||||||
for one_var in "${uniques_vars[@]}"
|
for one_var in "${uniques_vars[@]}"; do
|
||||||
do
|
|
||||||
# Validate that one_var is indeed defined
|
# Validate that one_var is indeed defined
|
||||||
# -v checks if the variable is defined, for example:
|
# -v checks if the variable is defined, for example:
|
||||||
# -v FOO tests if $FOO is defined
|
# -v FOO tests if $FOO is defined
|
||||||
|
@ -509,7 +489,7 @@ ynh_replace_vars () {
|
||||||
ynh_read_var_in_file() {
|
ynh_read_var_in_file() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fka
|
local legacy_args=fka
|
||||||
local -A args_array=( [f]=file= [k]=key= [a]=after=)
|
local -A args_array=([f]=file= [k]=key= [a]=after=)
|
||||||
local file
|
local file
|
||||||
local key
|
local key
|
||||||
local after
|
local after
|
||||||
|
@ -523,11 +503,9 @@ ynh_read_var_in_file() {
|
||||||
|
|
||||||
# Get the line number after which we search for the variable
|
# Get the line number after which we search for the variable
|
||||||
local line_number=1
|
local line_number=1
|
||||||
if [[ -n "$after" ]];
|
if [[ -n "$after" ]]; then
|
||||||
then
|
|
||||||
line_number=$(grep -n $after $file | cut -d: -f1)
|
line_number=$(grep -n $after $file | cut -d: -f1)
|
||||||
if [[ -z "$line_number" ]];
|
if [[ -z "$line_number" ]]; then
|
||||||
then
|
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
@ -564,12 +542,12 @@ ynh_read_var_in_file() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove comments if needed
|
# Remove comments if needed
|
||||||
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
local expression="$(echo "$expression_with_comment" | sed "s@${comments}[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||||
|
|
||||||
local first_char="${expression:0:1}"
|
local first_char="${expression:0:1}"
|
||||||
if [[ "$first_char" == '"' ]] ; then
|
if [[ "$first_char" == '"' ]]; then
|
||||||
echo "$expression" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
|
echo "$expression" | grep -m1 -o -P '"\K([^"](\\")?)*[^\\](?=")' | head -n1 | sed 's/\\"/"/g'
|
||||||
elif [[ "$first_char" == "'" ]] ; then
|
elif [[ "$first_char" == "'" ]]; then
|
||||||
echo "$expression" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
|
echo "$expression" | grep -m1 -o -P "'\K([^'](\\\\')?)*[^\\\\](?=')" | head -n1 | sed "s/\\\\'/'/g"
|
||||||
else
|
else
|
||||||
echo "$expression"
|
echo "$expression"
|
||||||
|
@ -588,7 +566,7 @@ ynh_read_var_in_file() {
|
||||||
ynh_write_var_in_file() {
|
ynh_write_var_in_file() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fkva
|
local legacy_args=fkva
|
||||||
local -A args_array=( [f]=file= [k]=key= [v]=value= [a]=after=)
|
local -A args_array=([f]=file= [k]=key= [v]=value= [a]=after=)
|
||||||
local file
|
local file
|
||||||
local key
|
local key
|
||||||
local value
|
local value
|
||||||
|
@ -603,11 +581,9 @@ ynh_write_var_in_file() {
|
||||||
|
|
||||||
# Get the line number after which we search for the variable
|
# Get the line number after which we search for the variable
|
||||||
local line_number=1
|
local line_number=1
|
||||||
if [[ -n "$after" ]];
|
if [[ -n "$after" ]]; then
|
||||||
then
|
|
||||||
line_number=$(grep -n $after $file | cut -d: -f1)
|
line_number=$(grep -n $after $file | cut -d: -f1)
|
||||||
if [[ -z "$line_number" ]];
|
if [[ -z "$line_number" ]]; then
|
||||||
then
|
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
@ -644,28 +620,28 @@ ynh_write_var_in_file() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove comments if needed
|
# Remove comments if needed
|
||||||
local expression="$(echo "$expression_with_comment" | sed "s@$comments[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
local expression="$(echo "$expression_with_comment" | sed "s@${comments}[^$string]*\$@@g" | sed "s@\s*[$endline]*\s*]*\$@@")"
|
||||||
endline=${expression_with_comment#"$expression"}
|
endline=${expression_with_comment#"$expression"}
|
||||||
endline="$(echo "$endline" | sed 's/\\/\\\\/g')"
|
endline="$(echo "$endline" | sed 's/\\/\\\\/g')"
|
||||||
value="$(echo "$value" | sed 's/\\/\\\\/g')"
|
value="$(echo "$value" | sed 's/\\/\\\\/g')"
|
||||||
local first_char="${expression:0:1}"
|
local first_char="${expression:0:1}"
|
||||||
delimiter=$'\001'
|
delimiter=$'\001'
|
||||||
if [[ "$first_char" == '"' ]] ; then
|
if [[ "$first_char" == '"' ]]; then
|
||||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||||
# So we need \\\\ to go through 2 sed
|
# So we need \\\\ to go through 2 sed
|
||||||
value="$(echo "$value" | sed 's/"/\\\\"/g')"
|
value="$(echo "$value" | sed 's/"/\\\\"/g')"
|
||||||
sed -ri "${range}s$delimiter"'(^'"${var_part}"'")([^"]|\\")*("[\s;,]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}"'"'"${endline}${delimiter}i" ${file}
|
sed -ri "${range}s$delimiter"'(^'"${var_part}"'")([^"]|\\")*("[\s;,]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}"'"'"${endline}${delimiter}i" ${file}
|
||||||
elif [[ "$first_char" == "'" ]] ; then
|
elif [[ "$first_char" == "'" ]]; then
|
||||||
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
# \ and sed is quite complex you need 2 \\ to get one in a sed
|
||||||
# However double quotes implies to double \\ to
|
# However double quotes implies to double \\ to
|
||||||
# So we need \\\\\\\\ to go through 2 sed and 1 double quotes str
|
# So we need \\\\\\\\ to go through 2 sed and 1 double quotes str
|
||||||
value="$(echo "$value" | sed "s/'/\\\\\\\\'/g")"
|
value="$(echo "$value" | sed "s/'/\\\\\\\\'/g")"
|
||||||
sed -ri "${range}s$delimiter(^${var_part}')([^']|\\')*('"'[\s,;]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}'${endline}${delimiter}i" ${file}
|
sed -ri "${range}s$delimiter(^${var_part}')([^']|\\')*('"'[\s,;]*)(\s*'$comments'.*)?$'$delimiter'\1'"${value}'${endline}${delimiter}i" ${file}
|
||||||
else
|
else
|
||||||
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] || [[ "$ext" =~ ^php|py|json|js$ ]] ; then
|
if [[ "$value" == *"'"* ]] || [[ "$value" == *'"'* ]] || [[ "$ext" =~ ^php|py|json|js$ ]]; then
|
||||||
value='\"'"$(echo "$value" | sed 's/"/\\\\"/g')"'\"'
|
value='\"'"$(echo "$value" | sed 's/"/\\\\"/g')"'\"'
|
||||||
fi
|
fi
|
||||||
if [[ "$ext" =~ ^yaml|yml$ ]] ; then
|
if [[ "$ext" =~ ^yaml|yml$ ]]; then
|
||||||
value=" $value"
|
value=" $value"
|
||||||
fi
|
fi
|
||||||
sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file}
|
sed -ri "${range}s$delimiter(^${var_part}).*\$$delimiter\1${value}${endline}${delimiter}i" ${file}
|
||||||
|
@ -673,7 +649,6 @@ ynh_write_var_in_file() {
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Render templates with Jinja2
|
# Render templates with Jinja2
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
|
@ -691,7 +666,7 @@ ynh_render_template() {
|
||||||
# Taken from https://stackoverflow.com/a/35009576
|
# Taken from https://stackoverflow.com/a/35009576
|
||||||
python3 -c 'import os, sys, jinja2; sys.stdout.write(
|
python3 -c 'import os, sys, jinja2; sys.stdout.write(
|
||||||
jinja2.Template(sys.stdin.read()
|
jinja2.Template(sys.stdin.read()
|
||||||
).render(os.environ));' < $template_path > $output_path
|
).render(os.environ));' <$template_path >$output_path
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fetch the Debian release codename
|
# Fetch the Debian release codename
|
||||||
|
@ -700,7 +675,7 @@ ynh_render_template() {
|
||||||
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
|
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.7.12 or higher.
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_get_debian_release () {
|
ynh_get_debian_release() {
|
||||||
echo $(lsb_release --codename --short)
|
echo $(lsb_release --codename --short)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,46 +699,55 @@ properly with chmod/chown."
|
||||||
echo $TMP_DIR
|
echo $TMP_DIR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_acceptable_path_to_delete() {
|
||||||
|
local file=$1
|
||||||
|
|
||||||
|
local forbidden_paths=$(ls -d / /* /{var,home,usr}/* /etc/{default,sudoers.d,yunohost,cron*})
|
||||||
|
|
||||||
|
# Legacy : A couple apps still have data in /home/$app ...
|
||||||
|
if [[ -n "$app" ]]
|
||||||
|
then
|
||||||
|
forbidden_paths=$(echo "$forbidden_paths" | grep -v "/home/$app")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use realpath to normalize the path ..
|
||||||
|
# i.e convert ///foo//bar//..///baz//// to /foo/baz
|
||||||
|
file=$(realpath --no-symlinks "$file")
|
||||||
|
if [ -z "$file" ] || grep -q -x -F "$file" <<< "$forbidden_paths"; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Remove a file or a directory securely
|
# Remove a file or a directory securely
|
||||||
#
|
#
|
||||||
# usage: ynh_secure_remove --file=path_to_remove
|
# usage: ynh_secure_remove --file=path_to_remove
|
||||||
# | arg: -f, --file= - File or directory to remove
|
# | arg: -f, --file= - File or directory to remove
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 2.6.4 or higher.
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_secure_remove () {
|
ynh_secure_remove() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
local -A args_array=( [f]=file= )
|
local -A args_array=([f]=file=)
|
||||||
local file
|
local file
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
set +o xtrace # set +x
|
set +o xtrace # set +x
|
||||||
|
|
||||||
local forbidden_path=" \
|
if [ $# -ge 2 ]; then
|
||||||
/var/www \
|
|
||||||
/home/yunohost.app"
|
|
||||||
|
|
||||||
if [ $# -ge 2 ]
|
|
||||||
then
|
|
||||||
ynh_print_warn --message="/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time."
|
ynh_print_warn --message="/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$file" ]]
|
if [[ -z "$file" ]]; then
|
||||||
then
|
|
||||||
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
|
ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring."
|
||||||
elif [[ "$forbidden_path" =~ "$file" \
|
elif [[ ! -e $file ]]; then
|
||||||
# Match all paths or subpaths in $forbidden_path
|
|
||||||
|| "$file" =~ ^/[[:alnum:]]+$ \
|
|
||||||
# Match all first level paths from / (Like /var, /root, etc...)
|
|
||||||
|| "${file:${#file}-1}" = "/" ]]
|
|
||||||
# Match if the path finishes by /. Because it seems there is an empty variable
|
|
||||||
then
|
|
||||||
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
|
|
||||||
elif [ -e "$file" ]
|
|
||||||
then
|
|
||||||
rm --recursive "$file"
|
|
||||||
else
|
|
||||||
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
ynh_print_info --message="'$file' wasn't deleted because it doesn't exist."
|
||||||
|
elif ! _acceptable_path_to_delete "$file"; then
|
||||||
|
ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete."
|
||||||
|
else
|
||||||
|
rm --recursive "$file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -o xtrace # set -x
|
set -o xtrace # set -x
|
||||||
|
@ -776,26 +760,22 @@ ynh_secure_remove () {
|
||||||
# (Deprecated, use --output-as json and jq instead)
|
# (Deprecated, use --output-as json and jq instead)
|
||||||
ynh_get_plain_key() {
|
ynh_get_plain_key() {
|
||||||
local prefix="#"
|
local prefix="#"
|
||||||
local founded=0
|
local found=0
|
||||||
# We call this key_ so that it's not caught as
|
# We call this key_ so that it's not caught as
|
||||||
# an info to be redacted by the core
|
# an info to be redacted by the core
|
||||||
local key_=$1
|
local key_=$1
|
||||||
shift
|
shift
|
||||||
while read line
|
while read line; do
|
||||||
do
|
if [[ "$found" == "1" ]]; then
|
||||||
if [[ "$founded" == "1" ]]
|
|
||||||
then
|
|
||||||
[[ "$line" =~ ^${prefix}[^#] ]] && return
|
[[ "$line" =~ ^${prefix}[^#] ]] && return
|
||||||
echo $line
|
echo $line
|
||||||
elif [[ "$line" =~ ^${prefix}${key_}$ ]]
|
elif [[ "$line" =~ ^${prefix}${key_}$ ]]; then
|
||||||
then
|
if [[ -n "${1:-}" ]]; then
|
||||||
if [[ -n "${1:-}" ]]
|
|
||||||
then
|
|
||||||
prefix+="#"
|
prefix+="#"
|
||||||
key_=$1
|
key_=$1
|
||||||
shift
|
shift
|
||||||
else
|
else
|
||||||
founded=1
|
found=1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -809,10 +789,10 @@ ynh_get_plain_key() {
|
||||||
# | ret: the value associate to that key
|
# | ret: the value associate to that key
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_read_manifest () {
|
ynh_read_manifest() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mk
|
local legacy_args=mk
|
||||||
local -A args_array=( [m]=manifest= [k]=manifest_key= )
|
local -A args_array=([m]=manifest= [k]=manifest_key=)
|
||||||
local manifest
|
local manifest
|
||||||
local manifest_key
|
local manifest_key
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -839,17 +819,16 @@ ynh_read_manifest () {
|
||||||
# For example, if the manifest contains `4.3-2~ynh3` the function will return `4.3-2`
|
# For example, if the manifest contains `4.3-2~ynh3` the function will return `4.3-2`
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_app_upstream_version () {
|
ynh_app_upstream_version() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
local -A args_array=( [m]=manifest= )
|
local -A args_array=([m]=manifest=)
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
manifest="${manifest:-}"
|
manifest="${manifest:-}"
|
||||||
|
|
||||||
if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]];
|
if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]]; then
|
||||||
then
|
|
||||||
version_key_=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
version_key_=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
|
||||||
else
|
else
|
||||||
version_key_=$YNH_APP_MANIFEST_VERSION
|
version_key_=$YNH_APP_MANIFEST_VERSION
|
||||||
|
@ -869,10 +848,10 @@ ynh_app_upstream_version () {
|
||||||
# For example, if the manifest contains `4.3-2~ynh3` the function will return `3`
|
# For example, if the manifest contains `4.3-2~ynh3` the function will return `3`
|
||||||
#
|
#
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_app_package_version () {
|
ynh_app_package_version() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
local -A args_array=( [m]=manifest= )
|
local -A args_array=([m]=manifest=)
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
@ -894,11 +873,10 @@ ynh_app_package_version () {
|
||||||
# sudo yunohost app upgrade <appname> --force
|
# sudo yunohost app upgrade <appname> --force
|
||||||
# ```
|
# ```
|
||||||
# Requires YunoHost version 3.5.0 or higher.
|
# Requires YunoHost version 3.5.0 or higher.
|
||||||
ynh_check_app_version_changed () {
|
ynh_check_app_version_changed() {
|
||||||
local return_value=${YNH_APP_UPGRADE_TYPE}
|
local return_value=${YNH_APP_UPGRADE_TYPE}
|
||||||
|
|
||||||
if [ "$return_value" == "UPGRADE_FULL" ] || [ "$return_value" == "UPGRADE_FORCED" ] || [ "$return_value" == "DOWNGRADE_FORCED" ]
|
if [ "$return_value" == "UPGRADE_FULL" ] || [ "$return_value" == "UPGRADE_FORCED" ] || [ "$return_value" == "DOWNGRADE_FORCED" ]; then
|
||||||
then
|
|
||||||
return_value="UPGRADE_APP"
|
return_value="UPGRADE_APP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -927,7 +905,7 @@ ynh_check_app_version_changed () {
|
||||||
# Requires YunoHost version 3.8.0 or higher.
|
# Requires YunoHost version 3.8.0 or higher.
|
||||||
ynh_compare_current_package_version() {
|
ynh_compare_current_package_version() {
|
||||||
local legacy_args=cv
|
local legacy_args=cv
|
||||||
declare -Ar args_array=( [c]=comparison= [v]=version= )
|
declare -Ar args_array=([c]=comparison= [v]=version=)
|
||||||
local version
|
local version
|
||||||
local comparison
|
local comparison
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -936,8 +914,7 @@ ynh_compare_current_package_version() {
|
||||||
local current_version=$YNH_APP_CURRENT_VERSION
|
local current_version=$YNH_APP_CURRENT_VERSION
|
||||||
|
|
||||||
# Check the syntax of the versions
|
# Check the syntax of the versions
|
||||||
if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]]
|
if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]]; then
|
||||||
then
|
|
||||||
ynh_die --message="Invalid argument for version."
|
ynh_die --message="Invalid argument for version."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -972,13 +949,11 @@ _ynh_apply_default_permissions() {
|
||||||
|
|
||||||
local ynh_requirement=$(jq -r '.requirements.yunohost' $YNH_APP_BASEDIR/manifest.json | tr -d '>= ')
|
local ynh_requirement=$(jq -r '.requirements.yunohost' $YNH_APP_BASEDIR/manifest.json | tr -d '>= ')
|
||||||
|
|
||||||
if [ -z "$ynh_requirement" ] || [ "$ynh_requirement" == "null" ] || dpkg --compare-versions $ynh_requirement ge 4.2
|
if [ -z "$ynh_requirement" ] || [ "$ynh_requirement" == "null" ] || dpkg --compare-versions $ynh_requirement ge 4.2; then
|
||||||
then
|
|
||||||
chmod o-rwx $target
|
chmod o-rwx $target
|
||||||
chmod g-w $target
|
chmod g-w $target
|
||||||
chown -R root:root $target
|
chown -R root:root $target
|
||||||
if ynh_system_user_exists $app
|
if ynh_system_user_exists $app; then
|
||||||
then
|
|
||||||
chown $app:$app $target
|
chown $app:$app $target
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -6,12 +6,11 @@ YNH_CWD="${YNH_BACKUP_DIR%/}/conf/manually_modified_files"
|
||||||
mkdir -p "$YNH_CWD"
|
mkdir -p "$YNH_CWD"
|
||||||
cd "$YNH_CWD"
|
cd "$YNH_CWD"
|
||||||
|
|
||||||
yunohost tools shell -c "from yunohost.regenconf import manually_modified_files; print('\n'.join(manually_modified_files()))" > ./manually_modified_files_list
|
yunohost tools shell -c "from yunohost.regenconf import manually_modified_files; print('\n'.join(manually_modified_files()))" >./manually_modified_files_list
|
||||||
|
|
||||||
ynh_backup --src_path="./manually_modified_files_list"
|
ynh_backup --src_path="./manually_modified_files_list"
|
||||||
|
|
||||||
for file in $(cat ./manually_modified_files_list)
|
for file in $(cat ./manually_modified_files_list); do
|
||||||
do
|
|
||||||
[[ -e $file ]] && ynh_backup --src_path="$file"
|
[[ -e $file ]] && ynh_backup --src_path="$file"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ do_init_regen() {
|
||||||
|
|
||||||
# set default current_host
|
# set default current_host
|
||||||
[[ -f /etc/yunohost/current_host ]] \
|
[[ -f /etc/yunohost/current_host ]] \
|
||||||
|| echo "yunohost.org" > /etc/yunohost/current_host
|
|| echo "yunohost.org" >/etc/yunohost/current_host
|
||||||
|
|
||||||
# copy default services and firewall
|
# copy default services and firewall
|
||||||
[[ -f /etc/yunohost/firewall.yml ]] \
|
[[ -f /etc/yunohost/firewall.yml ]] \
|
||||||
|
@ -45,7 +45,7 @@ do_init_regen() {
|
||||||
chown root:root /home/yunohost.backup/archives # This is later changed to admin:root once admin user exists
|
chown root:root /home/yunohost.backup/archives # This is later changed to admin:root once admin user exists
|
||||||
|
|
||||||
# Empty ssowat json persistent conf
|
# Empty ssowat json persistent conf
|
||||||
echo "{}" > '/etc/ssowat/conf.json.persistent'
|
echo "{}" >'/etc/ssowat/conf.json.persistent'
|
||||||
chmod 644 /etc/ssowat/conf.json.persistent
|
chmod 644 /etc/ssowat/conf.json.persistent
|
||||||
chown root:root /etc/ssowat/conf.json.persistent
|
chown root:root /etc/ssowat/conf.json.persistent
|
||||||
|
|
||||||
|
@ -82,19 +82,19 @@ do_pre_regen() {
|
||||||
# add cron job for diagnosis to be ran at 7h and 19h + a random delay between
|
# add cron job for diagnosis to be ran at 7h and 19h + a random delay between
|
||||||
# 0 and 20min, meant to avoid every instances running their diagnosis at
|
# 0 and 20min, meant to avoid every instances running their diagnosis at
|
||||||
# exactly the same time, which may overload the diagnosis server.
|
# exactly the same time, which may overload the diagnosis server.
|
||||||
cat > $pending_dir/etc/cron.d/yunohost-diagnosis << EOF
|
cat >$pending_dir/etc/cron.d/yunohost-diagnosis <<EOF
|
||||||
SHELL=/bin/bash
|
SHELL=/bin/bash
|
||||||
0 7,19 * * * root : YunoHost Automatic Diagnosis; sleep \$((RANDOM\\%1200)); yunohost diagnosis run --email > /dev/null 2>/dev/null || echo "Running the automatic diagnosis failed miserably"
|
0 7,19 * * * root : YunoHost Automatic Diagnosis; sleep \$((RANDOM\\%1200)); yunohost diagnosis run --email > /dev/null 2>/dev/null || echo "Running the automatic diagnosis failed miserably"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Cron job that upgrade the app list everyday
|
# Cron job that upgrade the app list everyday
|
||||||
cat > $pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog << EOF
|
cat >$pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
(sleep \$((RANDOM%3600)); yunohost tools update --apps > /dev/null) &
|
(sleep \$((RANDOM%3600)); yunohost tools update --apps > /dev/null) &
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Cron job that renew lets encrypt certificates if there's any that needs renewal
|
# Cron job that renew lets encrypt certificates if there's any that needs renewal
|
||||||
cat > $pending_dir/etc/cron.daily/yunohost-certificate-renew << EOF
|
cat >$pending_dir/etc/cron.daily/yunohost-certificate-renew <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
yunohost domain cert renew --email
|
yunohost domain cert renew --email
|
||||||
EOF
|
EOF
|
||||||
|
@ -102,9 +102,8 @@ EOF
|
||||||
# If we subscribed to a dyndns domain, add the corresponding cron
|
# If we subscribed to a dyndns domain, add the corresponding cron
|
||||||
# - delay between 0 and 60 secs to spread the check over a 1 min window
|
# - delay between 0 and 60 secs to spread the check over a 1 min window
|
||||||
# - do not run the command if some process already has the lock, to avoid queuing hundreds of commands...
|
# - do not run the command if some process already has the lock, to avoid queuing hundreds of commands...
|
||||||
if ls -l /etc/yunohost/dyndns/K*.private 2>/dev/null
|
if ls -l /etc/yunohost/dyndns/K*.private 2>/dev/null; then
|
||||||
then
|
cat >$pending_dir/etc/cron.d/yunohost-dyndns <<EOF
|
||||||
cat > $pending_dir/etc/cron.d/yunohost-dyndns << EOF
|
|
||||||
SHELL=/bin/bash
|
SHELL=/bin/bash
|
||||||
*/10 * * * * root : YunoHost DynDNS update; sleep \$((RANDOM\\%60)); test -e /var/run/moulinette_yunohost.lock || yunohost dyndns update >> /dev/null
|
*/10 * * * * root : YunoHost DynDNS update; sleep \$((RANDOM\\%60)); test -e /var/run/moulinette_yunohost.lock || yunohost dyndns update >> /dev/null
|
||||||
EOF
|
EOF
|
||||||
|
@ -121,11 +120,11 @@ EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
ConditionCapability=CAP_SYS_TIME
|
ConditionCapability=CAP_SYS_TIME
|
||||||
ConditionVirtualization=!container
|
ConditionVirtualization=!container
|
||||||
" > ${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf
|
" >${pending_dir}/etc/systemd/system/ntp.service.d/ynh-override.conf
|
||||||
|
|
||||||
# Make nftable conflict with yunohost-firewall
|
# Make nftable conflict with yunohost-firewall
|
||||||
mkdir -p ${pending_dir}/etc/systemd/system/nftables.service.d/
|
mkdir -p ${pending_dir}/etc/systemd/system/nftables.service.d/
|
||||||
cat > ${pending_dir}/etc/systemd/system/nftables.service.d/ynh-override.conf << EOF
|
cat >${pending_dir}/etc/systemd/system/nftables.service.d/ynh-override.conf <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
# yunohost-firewall and nftables conflict with each other
|
# yunohost-firewall and nftables conflict with each other
|
||||||
Conflicts=yunohost-firewall.service
|
Conflicts=yunohost-firewall.service
|
||||||
|
@ -135,7 +134,7 @@ EOF
|
||||||
|
|
||||||
# Don't suspend computer on LidSwitch
|
# Don't suspend computer on LidSwitch
|
||||||
mkdir -p ${pending_dir}/etc/systemd/logind.conf.d/
|
mkdir -p ${pending_dir}/etc/systemd/logind.conf.d/
|
||||||
cat > ${pending_dir}/etc/systemd/logind.conf.d/ynh-override.conf << EOF
|
cat >${pending_dir}/etc/systemd/logind.conf.d/ynh-override.conf <<EOF
|
||||||
[Login]
|
[Login]
|
||||||
HandleLidSwitch=ignore
|
HandleLidSwitch=ignore
|
||||||
HandleLidSwitchDocked=ignore
|
HandleLidSwitchDocked=ignore
|
||||||
|
@ -144,13 +143,13 @@ EOF
|
||||||
|
|
||||||
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
|
cp yunoprompt.service ${pending_dir}/etc/systemd/system/yunoprompt.service
|
||||||
|
|
||||||
if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]]
|
if [[ "$(yunohost settings get 'security.experimental.enabled')" == "True" ]]; then
|
||||||
then
|
|
||||||
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
cp proc-hidepid.service ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||||
else
|
else
|
||||||
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
touch ${pending_dir}/etc/systemd/system/proc-hidepid.service
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
mkdir -p ${pending_dir}/etc/dpkg/origins/
|
||||||
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
|
cp dpkg-origins ${pending_dir}/etc/dpkg/origins/yunohost
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -191,8 +190,7 @@ do_post_regen() {
|
||||||
setfacl -m g:all_users:--- /etc/yunohost
|
setfacl -m g:all_users:--- /etc/yunohost
|
||||||
setfacl -m g:all_users:--- /etc/ssowat
|
setfacl -m g:all_users:--- /etc/ssowat
|
||||||
|
|
||||||
for USER in $(yunohost user list --quiet --output-as json | jq -r '.users | .[] | .username')
|
for USER in $(yunohost user list --quiet --output-as json | jq -r '.users | .[] | .username'); do
|
||||||
do
|
|
||||||
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
|
[ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- /home/$USER
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -213,17 +211,18 @@ do_post_regen() {
|
||||||
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
|
grep -q '^sftp.app:' /etc/group || groupadd sftp.app
|
||||||
|
|
||||||
# Propagates changes in systemd service config overrides
|
# Propagates changes in systemd service config overrides
|
||||||
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || { systemctl daemon-reload; systemctl restart ntp; }
|
[[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart ntp
|
||||||
|
}
|
||||||
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
|
[[ ! "$regen_conf_files" =~ "nftables.service.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||||
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload
|
[[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || systemctl daemon-reload
|
||||||
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]
|
if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
|
||||||
then
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
|
action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
|
||||||
systemctl $action yunoprompt --quiet --now
|
systemctl $action yunoprompt --quiet --now
|
||||||
fi
|
fi
|
||||||
if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]
|
if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]; then
|
||||||
then
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
|
action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
|
||||||
systemctl $action proc-hidepid --quiet --now
|
systemctl $action proc-hidepid --quiet --now
|
||||||
|
|
|
@ -23,7 +23,7 @@ regen_local_ca() {
|
||||||
# (Update the serial so that it's specific to this very instance)
|
# (Update the serial so that it's specific to this very instance)
|
||||||
# N.B. : the weird RANDFILE thing comes from:
|
# N.B. : the weird RANDFILE thing comes from:
|
||||||
# https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
|
# https://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
|
||||||
RANDFILE=.rnd openssl rand -hex 19 > serial
|
RANDFILE=.rnd openssl rand -hex 19 >serial
|
||||||
rm -f index.txt
|
rm -f index.txt
|
||||||
touch index.txt
|
touch index.txt
|
||||||
cp /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf
|
cp /usr/share/yunohost/templates/ssl/openssl.cnf openssl.ca.cnf
|
||||||
|
@ -51,7 +51,7 @@ regen_local_ca() {
|
||||||
do_init_regen() {
|
do_init_regen() {
|
||||||
|
|
||||||
LOGFILE=/tmp/yunohost-ssl-init
|
LOGFILE=/tmp/yunohost-ssl-init
|
||||||
echo "" > $LOGFILE
|
echo "" >$LOGFILE
|
||||||
chown root:root $LOGFILE
|
chown root:root $LOGFILE
|
||||||
chmod 640 $LOGFILE
|
chmod 640 $LOGFILE
|
||||||
|
|
||||||
|
@ -110,8 +110,7 @@ do_post_regen() {
|
||||||
current_local_ca_domain=$(openssl x509 -in $ynh_ca -text | tr ',' '\n' | grep Issuer | awk '{print $4}')
|
current_local_ca_domain=$(openssl x509 -in $ynh_ca -text | tr ',' '\n' | grep Issuer | awk '{print $4}')
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
|
|
||||||
if [[ "$current_local_ca_domain" != "$main_domain" ]]
|
if [[ "$current_local_ca_domain" != "$main_domain" ]]; then
|
||||||
then
|
|
||||||
regen_local_ca $main_domain
|
regen_local_ca $main_domain
|
||||||
# Idk how useful this is, but this was in the previous python code (domain.main_domain())
|
# Idk how useful this is, but this was in the previous python code (domain.main_domain())
|
||||||
ln -sf /etc/yunohost/certs/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
|
ln -sf /etc/yunohost/certs/$domain/crt.pem /etc/ssl/certs/yunohost_crt.pem
|
||||||
|
|
|
@ -20,7 +20,7 @@ do_init_regen() {
|
||||||
rm -rf /var/backups/*.ldapdb
|
rm -rf /var/backups/*.ldapdb
|
||||||
rm -rf /var/backups/slapd-*
|
rm -rf /var/backups/slapd-*
|
||||||
|
|
||||||
debconf-set-selections << EOF
|
debconf-set-selections <<EOF
|
||||||
slapd slapd/password1 password yunohost
|
slapd slapd/password1 password yunohost
|
||||||
slapd slapd/password2 password yunohost
|
slapd slapd/password2 password yunohost
|
||||||
slapd slapd/domain string yunohost.org
|
slapd slapd/domain string yunohost.org
|
||||||
|
@ -62,8 +62,7 @@ EOF
|
||||||
# We don't use mkhomedir_helper because 'admin' may not be recognized
|
# We don't use mkhomedir_helper because 'admin' may not be recognized
|
||||||
# when this script is ran in a chroot (e.g. ISO install)
|
# when this script is ran in a chroot (e.g. ISO install)
|
||||||
# We also refer to admin as uid 1007 for the same reason
|
# We also refer to admin as uid 1007 for the same reason
|
||||||
if [ ! -d /home/admin ]
|
if [ ! -d /home/admin ]; then
|
||||||
then
|
|
||||||
cp -r /etc/skel /home/admin
|
cp -r /etc/skel /home/admin
|
||||||
chown -R 1007:1007 /home/admin
|
chown -R 1007:1007 /home/admin
|
||||||
fi
|
fi
|
||||||
|
@ -97,12 +96,12 @@ do_pre_regen() {
|
||||||
|
|
||||||
# Define if we need to migrate from hdb to mdb
|
# Define if we need to migrate from hdb to mdb
|
||||||
curr_backend=$(grep '^database' /etc/ldap/slapd.conf 2>/dev/null | awk '{print $2}')
|
curr_backend=$(grep '^database' /etc/ldap/slapd.conf 2>/dev/null | awk '{print $2}')
|
||||||
if [ -e /etc/ldap/slapd.conf ] && [ -n "$curr_backend" ] && \
|
if [ -e /etc/ldap/slapd.conf ] && [ -n "$curr_backend" ] \
|
||||||
[ $curr_backend != 'mdb' ]; then
|
&& [ $curr_backend != 'mdb' ]; then
|
||||||
backup_dir="/var/backups/dc=yunohost,dc=org-${curr_backend}-$(date +%s)"
|
backup_dir="/var/backups/dc=yunohost,dc=org-${curr_backend}-$(date +%s)"
|
||||||
mkdir -p "$backup_dir"
|
mkdir -p "$backup_dir"
|
||||||
slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif"
|
slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif"
|
||||||
echo "$backup_dir" > "$tmp_backup_dir_file"
|
echo "$backup_dir" >"$tmp_backup_dir_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# create needed directories
|
# create needed directories
|
||||||
|
@ -138,18 +137,16 @@ do_post_regen() {
|
||||||
chown -R openldap:openldap /etc/ldap/slapd.d/
|
chown -R openldap:openldap /etc/ldap/slapd.d/
|
||||||
|
|
||||||
# If we changed the systemd ynh-override conf
|
# If we changed the systemd ynh-override conf
|
||||||
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$"
|
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$"; then
|
||||||
then
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl restart slapd
|
systemctl restart slapd
|
||||||
sleep 3
|
sleep 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For some reason, old setups don't have the admins group defined...
|
# For some reason, old setups don't have the admins group defined...
|
||||||
if ! slapcat | grep -q 'cn=admins,ou=groups,dc=yunohost,dc=org'
|
if ! slapcat | grep -q 'cn=admins,ou=groups,dc=yunohost,dc=org'; then
|
||||||
then
|
|
||||||
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org <<< \
|
slapadd -F /etc/ldap/slapd.d -b dc=yunohost,dc=org <<< \
|
||||||
"dn: cn=admins,ou=groups,dc=yunohost,dc=org
|
"dn: cn=admins,ou=groups,dc=yunohost,dc=org
|
||||||
cn: admins
|
cn: admins
|
||||||
gidNumber: 4001
|
gidNumber: 4001
|
||||||
memberUid: admin
|
memberUid: admin
|
||||||
|
@ -192,8 +189,7 @@ objectClass: top"
|
||||||
# wait a maximum time of 5 minutes
|
# wait a maximum time of 5 minutes
|
||||||
# yes, force-reload behave like a restart
|
# yes, force-reload behave like a restart
|
||||||
number_of_wait=0
|
number_of_wait=0
|
||||||
while ! su admin -c '' && ((number_of_wait < 60))
|
while ! su admin -c '' && ((number_of_wait < 60)); do
|
||||||
do
|
|
||||||
sleep 5
|
sleep 5
|
||||||
((number_of_wait += 1))
|
((number_of_wait += 1))
|
||||||
done
|
done
|
||||||
|
|
|
@ -8,12 +8,11 @@ do_pre_regen() {
|
||||||
mkdir --parents "${pending_dir}/etc/apt/preferences.d"
|
mkdir --parents "${pending_dir}/etc/apt/preferences.d"
|
||||||
|
|
||||||
packages_to_refuse_from_sury="php php-fpm php-mysql php-xml php-zip php-mbstring php-ldap php-gd php-curl php-bz2 php-json php-sqlite3 php-intl openssl libssl1.1 libssl-dev"
|
packages_to_refuse_from_sury="php php-fpm php-mysql php-xml php-zip php-mbstring php-ldap php-gd php-curl php-bz2 php-json php-sqlite3 php-intl openssl libssl1.1 libssl-dev"
|
||||||
for package in $packages_to_refuse_from_sury
|
for package in $packages_to_refuse_from_sury; do
|
||||||
do
|
|
||||||
echo "
|
echo "
|
||||||
Package: $package
|
Package: $package
|
||||||
Pin: origin \"packages.sury.org\"
|
Pin: origin \"packages.sury.org\"
|
||||||
Pin-Priority: -1" >> "${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
Pin-Priority: -1" >>"${pending_dir}/etc/apt/preferences.d/extra_php_version"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
|
@ -43,7 +42,7 @@ Pin-Priority: -1
|
||||||
Package: bind9
|
Package: bind9
|
||||||
Pin: release *
|
Pin: release *
|
||||||
Pin-Priority: -1
|
Pin-Priority: -1
|
||||||
" >> "${pending_dir}/etc/apt/preferences.d/ban_packages"
|
" >>"${pending_dir}/etc/apt/preferences.d/ban_packages"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,13 @@ do_pre_regen() {
|
||||||
# install main conf file
|
# install main conf file
|
||||||
cat metronome.cfg.lua \
|
cat metronome.cfg.lua \
|
||||||
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
||||||
> "${metronome_dir}/metronome.cfg.lua"
|
>"${metronome_dir}/metronome.cfg.lua"
|
||||||
|
|
||||||
# add domain conf files
|
# add domain conf files
|
||||||
for domain in $YNH_DOMAINS; do
|
for domain in $YNH_DOMAINS; do
|
||||||
cat domain.tpl.cfg.lua \
|
cat domain.tpl.cfg.lua \
|
||||||
| sed "s/{{ domain }}/${domain}/g" \
|
| sed "s/{{ domain }}/${domain}/g" \
|
||||||
> "${metronome_conf_dir}/${domain}.cfg.lua"
|
>"${metronome_conf_dir}/${domain}.cfg.lua"
|
||||||
done
|
done
|
||||||
|
|
||||||
# remove old domain conf files
|
# remove old domain conf files
|
||||||
|
|
|
@ -32,8 +32,14 @@ do_init_regen() {
|
||||||
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
|
cp "redirect_to_admin.conf" $nginx_conf_dir/default.d/
|
||||||
|
|
||||||
# Restart nginx if conf looks good, otherwise display error and exit unhappy
|
# Restart nginx if conf looks good, otherwise display error and exit unhappy
|
||||||
nginx -t 2>/dev/null || { nginx -t; exit 1; }
|
nginx -t 2>/dev/null || {
|
||||||
systemctl restart nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
|
nginx -t
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
systemctl restart nginx || {
|
||||||
|
journalctl --no-pager --lines=10 -u nginx >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
@ -51,9 +57,8 @@ do_pre_regen() {
|
||||||
cp plain/* "$nginx_conf_dir"
|
cp plain/* "$nginx_conf_dir"
|
||||||
# remove the panel overlay if this is specified in settings
|
# remove the panel overlay if this is specified in settings
|
||||||
panel_overlay=$(yunohost settings get 'ssowat.panel_overlay.enabled')
|
panel_overlay=$(yunohost settings get 'ssowat.panel_overlay.enabled')
|
||||||
if [ "$panel_overlay" == "false" ] || [ "$panel_overlay" == "False" ]
|
if [ "$panel_overlay" == "false" ] || [ "$panel_overlay" == "False" ]; then
|
||||||
then
|
echo "#" >"${nginx_conf_dir}/yunohost_panel.conf.inc"
|
||||||
echo "#" > "${nginx_conf_dir}/yunohost_panel.conf.inc"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
|
@ -88,8 +93,7 @@ do_pre_regen() {
|
||||||
done
|
done
|
||||||
|
|
||||||
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.allowlist.enabled)
|
export webadmin_allowlist_enabled=$(yunohost settings get security.webadmin.allowlist.enabled)
|
||||||
if [ "$webadmin_allowlist_enabled" == "True" ]
|
if [ "$webadmin_allowlist_enabled" == "True" ]; then
|
||||||
then
|
|
||||||
export webadmin_allowlist=$(yunohost settings get security.webadmin.allowlist)
|
export webadmin_allowlist=$(yunohost settings get security.webadmin.allowlist)
|
||||||
fi
|
fi
|
||||||
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
|
ynh_render_template "yunohost_admin.conf.inc" "${nginx_conf_dir}/yunohost_admin.conf.inc"
|
||||||
|
@ -133,11 +137,9 @@ do_post_regen() {
|
||||||
# Get rid of legacy lets encrypt snippets
|
# Get rid of legacy lets encrypt snippets
|
||||||
for domain in $YNH_DOMAINS; do
|
for domain in $YNH_DOMAINS; do
|
||||||
# If the legacy letsencrypt / acme-challenge domain-specific snippet is still there
|
# If the legacy letsencrypt / acme-challenge domain-specific snippet is still there
|
||||||
if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ]
|
if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ]; then
|
||||||
then
|
|
||||||
# And if we're effectively including the new domain-independant snippet now
|
# And if we're effectively including the new domain-independant snippet now
|
||||||
if grep -q "include /etc/nginx/conf.d/acme-challenge.conf.inc;" /etc/nginx/conf.d/${domain}.conf
|
if grep -q "include /etc/nginx/conf.d/acme-challenge.conf.inc;" /etc/nginx/conf.d/${domain}.conf; then
|
||||||
then
|
|
||||||
# Delete the old domain-specific snippet
|
# Delete the old domain-specific snippet
|
||||||
rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf
|
rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf
|
||||||
fi
|
fi
|
||||||
|
@ -145,8 +147,14 @@ do_post_regen() {
|
||||||
done
|
done
|
||||||
|
|
||||||
# Reload nginx if conf looks good, otherwise display error and exit unhappy
|
# Reload nginx if conf looks good, otherwise display error and exit unhappy
|
||||||
nginx -t 2>/dev/null || { nginx -t; exit 1; }
|
nginx -t 2>/dev/null || {
|
||||||
pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; }
|
nginx -t
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
pgrep nginx && systemctl reload nginx || {
|
||||||
|
journalctl --no-pager --lines=10 -u nginx >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_$1_regen ${@:2}
|
do_$1_regen ${@:2}
|
||||||
|
|
|
@ -29,8 +29,7 @@ do_pre_regen() {
|
||||||
export relay_port=""
|
export relay_port=""
|
||||||
export relay_user=""
|
export relay_user=""
|
||||||
export relay_host="$(yunohost settings get 'smtp.relay.host')"
|
export relay_host="$(yunohost settings get 'smtp.relay.host')"
|
||||||
if [ -n "${relay_host}" ]
|
if [ -n "${relay_host}" ]; then
|
||||||
then
|
|
||||||
relay_port="$(yunohost settings get 'smtp.relay.port')"
|
relay_port="$(yunohost settings get 'smtp.relay.port')"
|
||||||
relay_user="$(yunohost settings get 'smtp.relay.user')"
|
relay_user="$(yunohost settings get 'smtp.relay.user')"
|
||||||
relay_password="$(yunohost settings get 'smtp.relay.password')"
|
relay_password="$(yunohost settings get 'smtp.relay.password')"
|
||||||
|
@ -42,7 +41,7 @@ do_pre_regen() {
|
||||||
chown postfix ${pending_dir}/etc/postfix
|
chown postfix ${pending_dir}/etc/postfix
|
||||||
chown postfix ${pending_dir}/etc/postfix/sasl_passwd
|
chown postfix ${pending_dir}/etc/postfix/sasl_passwd
|
||||||
|
|
||||||
cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd
|
cat <<<"[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" >${postfix_dir}/sasl_passwd
|
||||||
postmap ${postfix_dir}/sasl_passwd
|
postmap ${postfix_dir}/sasl_passwd
|
||||||
fi
|
fi
|
||||||
export main_domain
|
export main_domain
|
||||||
|
@ -52,7 +51,7 @@ do_pre_regen() {
|
||||||
cat postsrsd \
|
cat postsrsd \
|
||||||
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
| sed "s/{{ main_domain }}/${main_domain}/g" \
|
||||||
| sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \
|
| sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \
|
||||||
> "${default_dir}/postsrsd"
|
>"${default_dir}/postsrsd"
|
||||||
|
|
||||||
# adapt it for IPv4-only hosts
|
# adapt it for IPv4-only hosts
|
||||||
ipv6="$(yunohost settings get 'smtp.allow_ipv6')"
|
ipv6="$(yunohost settings get 'smtp.allow_ipv6')"
|
||||||
|
@ -69,8 +68,7 @@ do_pre_regen() {
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
if [ -e /etc/postfix/sasl_passwd ]
|
if [ -e /etc/postfix/sasl_passwd ]; then
|
||||||
then
|
|
||||||
chmod 750 /etc/postfix/sasl_passwd*
|
chmod 750 /etc/postfix/sasl_passwd*
|
||||||
chown postfix:root /etc/postfix/sasl_passwd*
|
chown postfix:root /etc/postfix/sasl_passwd*
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -40,7 +40,7 @@ do_post_regen() {
|
||||||
mkdir -p "/etc/dovecot/yunohost.d/post-ext.d"
|
mkdir -p "/etc/dovecot/yunohost.d/post-ext.d"
|
||||||
|
|
||||||
# create vmail user
|
# create vmail user
|
||||||
id vmail > /dev/null 2>&1 \
|
id vmail >/dev/null 2>&1 \
|
||||||
|| adduser --system --ingroup mail --uid 500 vmail --home /var/vmail --no-create-home
|
|| adduser --system --ingroup mail --uid 500 vmail --home /var/vmail --no-create-home
|
||||||
|
|
||||||
# Delete legacy home for vmail that existed in the past but was empty, poluting /home/
|
# Delete legacy home for vmail that existed in the past but was empty, poluting /home/
|
||||||
|
|
|
@ -14,8 +14,7 @@ do_pre_regen() {
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
regen_conf_files=$1
|
regen_conf_files=$1
|
||||||
|
|
||||||
if [[ ! -d /var/lib/mysql/mysql ]]
|
if [[ ! -d /var/lib/mysql/mysql ]]; then
|
||||||
then
|
|
||||||
# dpkg-reconfigure will initialize mysql (if it ain't already)
|
# dpkg-reconfigure will initialize mysql (if it ain't already)
|
||||||
# It enabled auth_socket for root, so no need to define any root password...
|
# It enabled auth_socket for root, so no need to define any root password...
|
||||||
# c.f. : cat /var/lib/dpkg/info/mariadb-server-10.3.postinst | grep install_db -C3
|
# c.f. : cat /var/lib/dpkg/info/mariadb-server-10.3.postinst | grep install_db -C3
|
||||||
|
@ -37,16 +36,14 @@ do_post_regen() {
|
||||||
# This is a trick to check if we're able to use mysql without password
|
# This is a trick to check if we're able to use mysql without password
|
||||||
# Expect instances installed in stretch to already have unix_socket
|
# Expect instances installed in stretch to already have unix_socket
|
||||||
#configured, but not old instances from the jessie/wheezy era
|
#configured, but not old instances from the jessie/wheezy era
|
||||||
if ! echo "" | mysql 2>/dev/null
|
if ! echo "" | mysql 2>/dev/null; then
|
||||||
then
|
|
||||||
password="$(cat /etc/yunohost/mysql)"
|
password="$(cat /etc/yunohost/mysql)"
|
||||||
# Enable plugin unix_socket for root on localhost
|
# Enable plugin unix_socket for root on localhost
|
||||||
mysql -u root -p"$password" <<< "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED WITH unix_socket WITH GRANT OPTION;"
|
mysql -u root -p"$password" <<<"GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED WITH unix_socket WITH GRANT OPTION;"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If now we're able to login without password, drop the mysql password
|
# If now we're able to login without password, drop the mysql password
|
||||||
if echo "" | mysql 2>/dev/null
|
if echo "" | mysql 2>/dev/null; then
|
||||||
then
|
|
||||||
rm /etc/yunohost/mysql
|
rm /etc/yunohost/mysql
|
||||||
else
|
else
|
||||||
echo "Can't connect to mysql using unix_socket auth ... something went wrong while trying to get rid of mysql password !?" >&2
|
echo "Can't connect to mysql using unix_socket auth ... something went wrong while trying to get rid of mysql password !?" >&2
|
||||||
|
@ -56,8 +53,7 @@ do_post_regen() {
|
||||||
# mysql is supposed to be an alias to mariadb... but in some weird case is not
|
# mysql is supposed to be an alias to mariadb... but in some weird case is not
|
||||||
# c.f. https://forum.yunohost.org/t/mysql-ne-fonctionne-pas/11661
|
# c.f. https://forum.yunohost.org/t/mysql-ne-fonctionne-pas/11661
|
||||||
# Playing with enable/disable allows to recreate the proper symlinks.
|
# Playing with enable/disable allows to recreate the proper symlinks.
|
||||||
if [ ! -e /etc/systemd/system/mysql.service ]
|
if [ ! -e /etc/systemd/system/mysql.service ]; then
|
||||||
then
|
|
||||||
systemctl stop mysql -q
|
systemctl stop mysql -q
|
||||||
systemctl disable mysql -q
|
systemctl disable mysql -q
|
||||||
systemctl disable mariadb -q
|
systemctl disable mariadb -q
|
||||||
|
|
|
@ -5,20 +5,12 @@ set -e
|
||||||
_generate_config() {
|
_generate_config() {
|
||||||
echo "domains:"
|
echo "domains:"
|
||||||
echo " - yunohost.local"
|
echo " - yunohost.local"
|
||||||
for domain in $YNH_DOMAINS
|
for domain in $YNH_DOMAINS; do
|
||||||
do
|
|
||||||
# Only keep .local domains (don't keep
|
# Only keep .local domains (don't keep
|
||||||
[[ "$domain" =~ [^.]+\.[^.]+\.local$ ]] && echo "Subdomain $domain cannot be handled by Bonjour/Zeroconf/mDNS" >&2
|
[[ "$domain" =~ [^.]+\.[^.]+\.local$ ]] && echo "Subdomain $domain cannot be handled by Bonjour/Zeroconf/mDNS" >&2
|
||||||
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
|
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
|
||||||
echo " - $domain"
|
echo " - $domain"
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "interfaces:"
|
|
||||||
local_network_interfaces="$(ip --brief a | grep ' 10\.\| 192\.168\.' | awk '{print $1}')"
|
|
||||||
for interface in $local_network_interfaces
|
|
||||||
do
|
|
||||||
echo " - $interface"
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_init_regen() {
|
do_init_regen() {
|
||||||
|
@ -37,7 +29,7 @@ do_pre_regen() {
|
||||||
getent passwd mdns &>/dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group mdns
|
getent passwd mdns &>/dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group mdns
|
||||||
|
|
||||||
mkdir -p ${pending_dir}/etc/yunohost
|
mkdir -p ${pending_dir}/etc/yunohost
|
||||||
_generate_config > ${pending_dir}/etc/yunohost/mdns.yml
|
_generate_config >${pending_dir}/etc/yunohost/mdns.yml
|
||||||
}
|
}
|
||||||
|
|
||||||
do_post_regen() {
|
do_post_regen() {
|
||||||
|
@ -46,14 +38,12 @@ do_post_regen() {
|
||||||
chown mdns:mdns /etc/yunohost/mdns.yml
|
chown mdns:mdns /etc/yunohost/mdns.yml
|
||||||
|
|
||||||
# If we changed the systemd ynh-override conf
|
# If we changed the systemd ynh-override conf
|
||||||
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/yunomdns.service$"
|
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/yunomdns.service$"; then
|
||||||
then
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Legacy stuff to enable the new yunomdns service on legacy systems
|
# Legacy stuff to enable the new yunomdns service on legacy systems
|
||||||
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf
|
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then
|
||||||
then
|
|
||||||
systemctl enable yunomdns
|
systemctl enable yunomdns
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ do_pre_regen() {
|
||||||
cp plain/dnsmasq.conf ${pending_dir}/etc/dnsmasq.conf
|
cp plain/dnsmasq.conf ${pending_dir}/etc/dnsmasq.conf
|
||||||
|
|
||||||
# add resolver file
|
# add resolver file
|
||||||
cat plain/resolv.dnsmasq.conf | grep "^nameserver" | shuf > ${pending_dir}/etc/resolv.dnsmasq.conf
|
cat plain/resolv.dnsmasq.conf | grep "^nameserver" | shuf >${pending_dir}/etc/resolv.dnsmasq.conf
|
||||||
|
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
ipv4=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
|
ipv4=$(curl -s -4 https://ip.yunohost.org 2>/dev/null || true)
|
||||||
|
@ -32,6 +32,7 @@ do_pre_regen() {
|
||||||
|
|
||||||
# add domain conf files
|
# add domain conf files
|
||||||
for domain in $YNH_DOMAINS; do
|
for domain in $YNH_DOMAINS; do
|
||||||
|
[[ ! $domain =~ \.local$ ]] || continue
|
||||||
export domain
|
export domain
|
||||||
ynh_render_template "domain.tpl" "${dnsmasq_dir}/${domain}"
|
ynh_render_template "domain.tpl" "${dnsmasq_dir}/${domain}"
|
||||||
done
|
done
|
||||||
|
@ -40,8 +41,10 @@ do_pre_regen() {
|
||||||
conf_files=$(ls -1 /etc/dnsmasq.d \
|
conf_files=$(ls -1 /etc/dnsmasq.d \
|
||||||
| awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }')
|
| awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }')
|
||||||
for domain in $conf_files; do
|
for domain in $conf_files; do
|
||||||
[[ $YNH_DOMAINS =~ $domain ]] \
|
if [[ ! $YNH_DOMAINS =~ $domain ]] && [[ ! $domain =~ \.local$ ]]
|
||||||
|| touch "${dnsmasq_dir}/${domain}"
|
then
|
||||||
|
touch "${dnsmasq_dir}/${domain}"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,16 +53,14 @@ do_post_regen() {
|
||||||
|
|
||||||
# Fuck it, those domain/search entries from dhclient are usually annoying
|
# Fuck it, those domain/search entries from dhclient are usually annoying
|
||||||
# lying shit from the ISP trying to MiTM
|
# lying shit from the ISP trying to MiTM
|
||||||
if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf
|
if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf; then
|
||||||
then
|
if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null; then
|
||||||
if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null
|
|
||||||
then
|
|
||||||
sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient
|
sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient
|
||||||
fi
|
fi
|
||||||
|
|
||||||
grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >> /etc/dhcp/dhclient.conf
|
grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >>/etc/dhcp/dhclient.conf
|
||||||
grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >> /etc/dhcp/dhclient.conf
|
grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >>/etc/dhcp/dhclient.conf
|
||||||
grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >> /etc/dhcp/dhclient.conf
|
grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >>/etc/dhcp/dhclient.conf
|
||||||
systemctl restart resolvconf
|
systemctl restart resolvconf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -71,8 +72,7 @@ do_post_regen() {
|
||||||
[[ -n "$regen_conf_files" ]] || return
|
[[ -n "$regen_conf_files" ]] || return
|
||||||
|
|
||||||
# Remove / disable services likely to conflict with dnsmasq
|
# Remove / disable services likely to conflict with dnsmasq
|
||||||
for SERVICE in systemd-resolved bind9
|
for SERVICE in systemd-resolved bind9; do
|
||||||
do
|
|
||||||
systemctl is-enabled $SERVICE &>/dev/null && systemctl disable $SERVICE 2>/dev/null
|
systemctl is-enabled $SERVICE &>/dev/null && systemctl disable $SERVICE 2>/dev/null
|
||||||
systemctl is-active $SERVICE &>/dev/null && systemctl stop $SERVICE
|
systemctl is-active $SERVICE &>/dev/null && systemctl stop $SERVICE
|
||||||
done
|
done
|
||||||
|
|
|
@ -8,13 +8,16 @@ from publicsuffix import PublicSuffixList
|
||||||
|
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output
|
||||||
|
|
||||||
from yunohost.utils.dns import dig, YNH_DYNDNS_DOMAINS
|
from yunohost.utils.dns import (
|
||||||
|
dig,
|
||||||
|
YNH_DYNDNS_DOMAINS,
|
||||||
|
is_yunohost_dyndns_domain,
|
||||||
|
is_special_use_tld,
|
||||||
|
)
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list, _get_maindomain
|
from yunohost.domain import domain_list, _get_maindomain
|
||||||
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
|
from yunohost.dns import _build_dns_conf, _get_dns_zone_for_domain
|
||||||
|
|
||||||
SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"]
|
|
||||||
|
|
||||||
|
|
||||||
class DNSRecordsDiagnoser(Diagnoser):
|
class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
|
@ -26,23 +29,20 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
main_domain = _get_maindomain()
|
main_domain = _get_maindomain()
|
||||||
|
|
||||||
all_domains = domain_list(exclude_subdomains=True)["domains"]
|
major_domains = domain_list(exclude_subdomains=True)["domains"]
|
||||||
for domain in all_domains:
|
for domain in major_domains:
|
||||||
self.logger_debug("Diagnosing DNS conf for %s" % domain)
|
self.logger_debug("Diagnosing DNS conf for %s" % domain)
|
||||||
is_specialusedomain = any(
|
|
||||||
domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS
|
|
||||||
)
|
|
||||||
for report in self.check_domain(
|
for report in self.check_domain(
|
||||||
domain,
|
domain,
|
||||||
domain == main_domain,
|
domain == main_domain,
|
||||||
is_specialusedomain=is_specialusedomain,
|
|
||||||
):
|
):
|
||||||
yield report
|
yield report
|
||||||
|
|
||||||
# Check if a domain buy by the user will expire soon
|
# Check if a domain buy by the user will expire soon
|
||||||
psl = PublicSuffixList()
|
psl = PublicSuffixList()
|
||||||
domains_from_registrar = [
|
domains_from_registrar = [
|
||||||
psl.get_public_suffix(domain) for domain in all_domains
|
psl.get_public_suffix(domain) for domain in major_domains
|
||||||
]
|
]
|
||||||
domains_from_registrar = [
|
domains_from_registrar = [
|
||||||
domain for domain in domains_from_registrar if "." in domain
|
domain for domain in domains_from_registrar if "." in domain
|
||||||
|
@ -53,7 +53,16 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
for report in self.check_expiration_date(domains_from_registrar):
|
for report in self.check_expiration_date(domains_from_registrar):
|
||||||
yield report
|
yield report
|
||||||
|
|
||||||
def check_domain(self, domain, is_main_domain, is_specialusedomain):
|
def check_domain(self, domain, is_main_domain):
|
||||||
|
|
||||||
|
if is_special_use_tld(domain):
|
||||||
|
categories = []
|
||||||
|
yield dict(
|
||||||
|
meta={"domain": domain},
|
||||||
|
data={},
|
||||||
|
status="INFO",
|
||||||
|
summary="diagnosis_dns_specialusedomain",
|
||||||
|
)
|
||||||
|
|
||||||
base_dns_zone = _get_dns_zone_for_domain(domain)
|
base_dns_zone = _get_dns_zone_for_domain(domain)
|
||||||
basename = domain.replace(base_dns_zone, "").rstrip(".") or "@"
|
basename = domain.replace(base_dns_zone, "").rstrip(".") or "@"
|
||||||
|
@ -64,15 +73,6 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
categories = ["basic", "mail", "xmpp", "extra"]
|
categories = ["basic", "mail", "xmpp", "extra"]
|
||||||
|
|
||||||
if is_specialusedomain:
|
|
||||||
categories = []
|
|
||||||
yield dict(
|
|
||||||
meta={"domain": domain},
|
|
||||||
data={},
|
|
||||||
status="INFO",
|
|
||||||
summary="diagnosis_dns_specialusedomain",
|
|
||||||
)
|
|
||||||
|
|
||||||
for category in categories:
|
for category in categories:
|
||||||
|
|
||||||
records = expected_configuration[category]
|
records = expected_configuration[category]
|
||||||
|
@ -84,7 +84,8 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
id_ = r["type"] + ":" + r["name"]
|
id_ = r["type"] + ":" + r["name"]
|
||||||
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
|
fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain
|
||||||
|
|
||||||
# Ugly hack to not check mail records for subdomains stuff, otherwise will end up in a shitstorm of errors for people with many subdomains...
|
# Ugly hack to not check mail records for subdomains stuff,
|
||||||
|
# otherwise will end up in a shitstorm of errors for people with many subdomains...
|
||||||
# Should find a cleaner solution in the suggested conf...
|
# Should find a cleaner solution in the suggested conf...
|
||||||
if r["type"] in ["MX", "TXT"] and fqdn not in [
|
if r["type"] in ["MX", "TXT"] and fqdn not in [
|
||||||
domain,
|
domain,
|
||||||
|
@ -131,6 +132,12 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
status = "SUCCESS"
|
status = "SUCCESS"
|
||||||
summary = "diagnosis_dns_good_conf"
|
summary = "diagnosis_dns_good_conf"
|
||||||
|
|
||||||
|
# If status is okay and there's actually no expected records
|
||||||
|
# (e.g. XMPP disabled)
|
||||||
|
# then let's not yield any diagnosis line
|
||||||
|
if not records and "status" == "SUCCESS":
|
||||||
|
continue
|
||||||
|
|
||||||
output = dict(
|
output = dict(
|
||||||
meta={"domain": domain, "category": category},
|
meta={"domain": domain, "category": category},
|
||||||
data=results,
|
data=results,
|
||||||
|
@ -140,10 +147,7 @@ class DNSRecordsDiagnoser(Diagnoser):
|
||||||
|
|
||||||
if discrepancies:
|
if discrepancies:
|
||||||
# For ynh-managed domains (nohost.me etc...), tell people to try to "yunohost dyndns update --force"
|
# For ynh-managed domains (nohost.me etc...), tell people to try to "yunohost dyndns update --force"
|
||||||
if any(
|
if is_yunohost_dyndns_domain(domain):
|
||||||
domain.endswith(ynh_dyndns_domain)
|
|
||||||
for ynh_dyndns_domain in YNH_DYNDNS_DOMAINS
|
|
||||||
):
|
|
||||||
output["details"] = ["diagnosis_dns_try_dyndns_update_force"]
|
output["details"] = ["diagnosis_dns_try_dyndns_update_force"]
|
||||||
# Otherwise point to the documentation
|
# Otherwise point to the documentation
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -8,6 +8,7 @@ from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.diagnosis import Diagnoser
|
from yunohost.diagnosis import Diagnoser
|
||||||
from yunohost.domain import domain_list
|
from yunohost.domain import domain_list
|
||||||
|
from yunohost.utils.dns import is_special_use_tld
|
||||||
|
|
||||||
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
DIAGNOSIS_SERVER = "diagnosis.yunohost.org"
|
||||||
|
|
||||||
|
@ -34,11 +35,11 @@ class WebDiagnoser(Diagnoser):
|
||||||
summary="diagnosis_http_nginx_conf_not_up_to_date",
|
summary="diagnosis_http_nginx_conf_not_up_to_date",
|
||||||
details=["diagnosis_http_nginx_conf_not_up_to_date_details"],
|
details=["diagnosis_http_nginx_conf_not_up_to_date_details"],
|
||||||
)
|
)
|
||||||
elif domain.endswith(".local"):
|
elif is_special_use_tld(domain):
|
||||||
yield dict(
|
yield dict(
|
||||||
meta={"domain": domain},
|
meta={"domain": domain},
|
||||||
status="INFO",
|
status="INFO",
|
||||||
summary="diagnosis_http_localdomain",
|
summary="diagnosis_http_special_use_tld",
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
domains_to_check.append(domain)
|
domains_to_check.append(domain)
|
||||||
|
|
|
@ -76,7 +76,7 @@ class AppDiagnoser(Diagnoser):
|
||||||
for deprecated_helper in deprecated_helpers:
|
for deprecated_helper in deprecated_helpers:
|
||||||
if (
|
if (
|
||||||
os.system(
|
os.system(
|
||||||
f"grep -hr '{deprecated_helper}' {app['setting_path']}/scripts/ | grep -v -q '^\s*#'"
|
f"grep -hr '{deprecated_helper}' {app['setting_path']}/scripts/ | grep -v -q '^\\s*#'"
|
||||||
)
|
)
|
||||||
== 0
|
== 0
|
||||||
):
|
):
|
||||||
|
|
|
@ -14,11 +14,11 @@ die() {
|
||||||
|
|
||||||
# Restore saved configuration and database
|
# Restore saved configuration and database
|
||||||
[[ $state -ge 1 ]] \
|
[[ $state -ge 1 ]] \
|
||||||
&& (rm -rf /etc/ldap/slapd.d &&
|
&& (rm -rf /etc/ldap/slapd.d \
|
||||||
mv "${TMPDIR}/slapd.d" /etc/ldap/slapd.d)
|
&& mv "${TMPDIR}/slapd.d" /etc/ldap/slapd.d)
|
||||||
[[ $state -ge 2 ]] \
|
[[ $state -ge 2 ]] \
|
||||||
&& (rm -rf /var/lib/ldap &&
|
&& (rm -rf /var/lib/ldap \
|
||||||
mv "${TMPDIR}/ldap" /var/lib/ldap)
|
&& mv "${TMPDIR}/ldap" /var/lib/ldap)
|
||||||
chown -R openldap: /etc/ldap/slapd.d /var/lib/ldap
|
chown -R openldap: /etc/ldap/slapd.d /var/lib/ldap
|
||||||
|
|
||||||
systemctl start slapd
|
systemctl start slapd
|
||||||
|
|
|
@ -5,8 +5,7 @@ ynh_abort_if_errors
|
||||||
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/manually_modified_files"
|
YNH_CWD="${YNH_BACKUP_DIR%/}/conf/manually_modified_files"
|
||||||
cd "$YNH_CWD"
|
cd "$YNH_CWD"
|
||||||
|
|
||||||
for file in $(cat ./manually_modified_files_list)
|
for file in $(cat ./manually_modified_files_list); do
|
||||||
do
|
|
||||||
ynh_restore_file --origin_path="$file" --not_mandatory
|
ynh_restore_file --origin_path="$file" --not_mandatory
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,20 @@ service quota-warning {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
service stats {
|
||||||
|
unix_listener stats-reader {
|
||||||
|
user = vmail
|
||||||
|
group = mail
|
||||||
|
mode = 0660
|
||||||
|
}
|
||||||
|
|
||||||
|
unix_listener stats-writer {
|
||||||
|
user = vmail
|
||||||
|
group = mail
|
||||||
|
mode = 0660
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plugin {
|
plugin {
|
||||||
sieve = /var/mail/sievescript/%n/.dovecot.sieve
|
sieve = /var/mail/sievescript/%n/.dovecot.sieve
|
||||||
sieve_dir = /var/mail/sievescript/%n/scripts/
|
sieve_dir = /var/mail/sievescript/%n/scripts/
|
||||||
|
|
|
@ -6,6 +6,7 @@ After=network.target
|
||||||
User=mdns
|
User=mdns
|
||||||
Group=mdns
|
Group=mdns
|
||||||
Type=simple
|
Type=simple
|
||||||
|
Environment=PYTHONUNBUFFERED=1
|
||||||
ExecStart=/usr/bin/yunomdns
|
ExecStart=/usr/bin/yunomdns
|
||||||
StandardOutput=syslog
|
StandardOutput=syslog
|
||||||
|
|
||||||
|
|
45
debian/changelog
vendored
45
debian/changelog
vendored
|
@ -1,3 +1,48 @@
|
||||||
|
yunohost (4.3.1.3) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] app: repo url branch names may contain dots (38cff4a9)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 07 Oct 2021 18:31:09 +0200
|
||||||
|
|
||||||
|
yunohost (4.3.1.2) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] apps: upgrade was broken because of typo ([#1350](https://github.com/YunoHost/yunohost/pull/1350))
|
||||||
|
- [enh] apps: in app_info, return a new is_webapp info meant to be used by API/webadmin (4cd5e9b6)
|
||||||
|
- [fix] configpanel: handle case where file question didnt get modified from webadmin, in which case self.value contains a path (54d901ad)
|
||||||
|
- [fix] configpanel: bind_key -> bind_key_ to prevent yunohost from redacting key names which leads to broken log metadata.yml somehow (941cc294)
|
||||||
|
- [enh] questions: Add visible attribute support in cli (74256845)
|
||||||
|
- [enh] helpers: Simplify apt/php dependencies helpers ([#1018](https://github.com/YunoHost/yunohost/pull/1018))
|
||||||
|
- [enh] helpers: In logrotate helper, enforce decent permissions on log file if app user exists ([#1352](https://github.com/YunoHost/yunohost/pull/1352))
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Éric Gaspar, Kay0u, ljf)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 07 Oct 2021 10:42:06 +0200
|
||||||
|
|
||||||
|
yunohost (4.3.1.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [enh] app helpers: Update n version ([#1347](https://github.com/YunoHost/yunohost/pull/1347))
|
||||||
|
- [enh] Misc app.py refactoring + Prevent change_url from being used to move a fulldomain app to a subpath ([#1346](https://github.com/YunoHost/yunohost/pull/1346))
|
||||||
|
- [i18n] Translations updated for French, Galician, Portuguese, Ukrainian
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Éric Gaspar, José M, mifegui, ppr, Tymofii-Lytvynenko)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 04 Oct 2021 01:33:22 +0200
|
||||||
|
|
||||||
|
yunohost (4.3.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] diagnosis: new app diagnosis grep reporing comments as issues ([#1333](https://github.com/YunoHost/yunohost/pull/1333))
|
||||||
|
- [enh] configpanel: Bind function for hotspot (79126809)
|
||||||
|
- [enh] cli: Rework/improve prompt mecanic ([#1338](https://github.com/YunoHost/yunohost/pull/1338))
|
||||||
|
- [fix] dyndns update broke because of buggy dns record names (da1b9089)
|
||||||
|
- [enh] dns: general improvement for special-use TLD / ynh dyndns domains (17aafe6f)
|
||||||
|
- [fix] yunomdns: various fixes/improvements ([#1335](https://github.com/YunoHost/yunohost/pull/1335))
|
||||||
|
- [fix] certs: Adapt ready_for_ACME check to the new dnsrecord result format... (d75c1a61)
|
||||||
|
- [i18n] Translations updated for French
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Éric Gaspar, Félix Piédallu, Kayou, ljf, tituspijean)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 29 Sep 2021 22:22:42 +0200
|
||||||
|
|
||||||
yunohost (4.3.0) testing; urgency=low
|
yunohost (4.3.0) testing; urgency=low
|
||||||
|
|
||||||
- [users] Import/export users from/to CSV ([#1089](https://github.com/YunoHost/yunohost/pull/1089))
|
- [users] Import/export users from/to CSV ([#1089](https://github.com/YunoHost/yunohost/pull/1089))
|
||||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -10,7 +10,7 @@ Package: yunohost
|
||||||
Essential: yes
|
Essential: yes
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: ${python3:Depends}, ${misc:Depends}
|
Depends: ${python3:Depends}, ${misc:Depends}
|
||||||
, moulinette (>= 4.2), ssowat (>= 4.0)
|
, moulinette (>= 4.3), ssowat (>= 4.3)
|
||||||
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
, python3-psutil, python3-requests, python3-dnspython, python3-openssl
|
||||||
, python3-miniupnpc, python3-dbus, python3-jinja2
|
, python3-miniupnpc, python3-dbus, python3-jinja2
|
||||||
, python3-toml, python3-packaging, python3-publicsuffix,
|
, python3-toml, python3-packaging, python3-publicsuffix,
|
||||||
|
|
7
debian/postinst
vendored
7
debian/postinst
vendored
|
@ -11,8 +11,7 @@ do_configure() {
|
||||||
if [ ! -f /etc/yunohost/installed ]; then
|
if [ ! -f /etc/yunohost/installed ]; then
|
||||||
# If apps/ is not empty, we're probably already installed in the past and
|
# If apps/ is not empty, we're probably already installed in the past and
|
||||||
# something funky happened ...
|
# something funky happened ...
|
||||||
if [ -d /etc/yunohost/apps/ ] && ls /etc/yunohost/apps/* >/dev/null 2>&1
|
if [ -d /etc/yunohost/apps/ ] && ls /etc/yunohost/apps/* >/dev/null 2>&1; then
|
||||||
then
|
|
||||||
echo "Sounds like /etc/yunohost/installed mysteriously disappeared ... You should probably contact the Yunohost support ..."
|
echo "Sounds like /etc/yunohost/installed mysteriously disappeared ... You should probably contact the Yunohost support ..."
|
||||||
else
|
else
|
||||||
bash /usr/share/yunohost/hooks/conf_regen/01-yunohost init
|
bash /usr/share/yunohost/hooks/conf_regen/01-yunohost init
|
||||||
|
@ -51,8 +50,8 @@ case "$1" in
|
||||||
configure)
|
configure)
|
||||||
do_configure
|
do_configure
|
||||||
;;
|
;;
|
||||||
abort-upgrade|abort-remove|abort-deconfigure)
|
abort-upgrade | abort-remove | abort-deconfigure) ;;
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "postinst called with unknown argument \`$1'" >&2
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -13,10 +13,8 @@
|
||||||
"app_already_installed": "{app} is already installed",
|
"app_already_installed": "{app} is already installed",
|
||||||
"app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Check in `app changeurl` if it's available.",
|
"app_already_installed_cant_change_url": "This app is already installed. The URL cannot be changed just by this function. Check in `app changeurl` if it's available.",
|
||||||
"app_already_up_to_date": "{app} is already up-to-date",
|
"app_already_up_to_date": "{app} is already up-to-date",
|
||||||
"app_argument_choice_invalid": "Use one of these choices '{choices}' for the argument '{name}' instead of '{value}'",
|
"app_argument_choice_invalid": "Pick a valid value for argument '{name}': '{value}' is not among the available choices ({choices})",
|
||||||
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
|
"app_argument_invalid": "Pick a valid value for the argument '{name}': {error}",
|
||||||
"app_argument_password_help_keep": "Press Enter to keep the current value",
|
|
||||||
"app_argument_password_help_optional": "Type one space to empty the password",
|
|
||||||
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason",
|
"app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason",
|
||||||
"app_argument_required": "Argument '{name}' is required",
|
"app_argument_required": "Argument '{name}' is required",
|
||||||
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.",
|
"app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain}{path}'), nothing to do.",
|
||||||
|
@ -38,7 +36,6 @@
|
||||||
"app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?",
|
"app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?",
|
||||||
"app_manifest_install_ask_password": "Choose an administration password for this app",
|
"app_manifest_install_ask_password": "Choose an administration password for this app",
|
||||||
"app_manifest_install_ask_path": "Choose the URL path (after the domain) where this app should be installed",
|
"app_manifest_install_ask_path": "Choose the URL path (after the domain) where this app should be installed",
|
||||||
"app_manifest_invalid": "Something is wrong with the app manifest: {error}",
|
|
||||||
"app_not_correctly_installed": "{app} seems to be incorrectly installed",
|
"app_not_correctly_installed": "{app} seems to be incorrectly installed",
|
||||||
"app_not_installed": "Could not find {app} in the list of installed apps: {all_apps}",
|
"app_not_installed": "Could not find {app} in the list of installed apps: {all_apps}",
|
||||||
"app_not_properly_removed": "{app} has not been properly removed",
|
"app_not_properly_removed": "{app} has not been properly removed",
|
||||||
|
@ -194,7 +191,7 @@
|
||||||
"diagnosis_dns_good_conf": "DNS records are correctly configured for domain {domain} (category {category})",
|
"diagnosis_dns_good_conf": "DNS records are correctly configured for domain {domain} (category {category})",
|
||||||
"diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Value: <code>{value}</code>",
|
"diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Value: <code>{value}</code>",
|
||||||
"diagnosis_dns_point_to_doc": "Please check the documentation at <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> if you need help about configuring DNS records.",
|
"diagnosis_dns_point_to_doc": "Please check the documentation at <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> if you need help about configuring DNS records.",
|
||||||
"diagnosis_dns_specialusedomain": "Domain {domain} is based on a special-use top-level domain (TLD) and is therefore not expected to have actual DNS records.",
|
"diagnosis_dns_specialusedomain": "Domain {domain} is based on a special-use top-level domain (TLD) such as .local or .test and is therefore not expected to have actual DNS records.",
|
||||||
"diagnosis_dns_try_dyndns_update_force": "This domain's DNS configuration should automatically be managed by YunoHost. If that's not the case, you can try to force an update using <cmd>yunohost dyndns update --force</cmd>.",
|
"diagnosis_dns_try_dyndns_update_force": "This domain's DNS configuration should automatically be managed by YunoHost. If that's not the case, you can try to force an update using <cmd>yunohost dyndns update --force</cmd>.",
|
||||||
"diagnosis_domain_expiration_error": "Some domains will expire VERY SOON!",
|
"diagnosis_domain_expiration_error": "Some domains will expire VERY SOON!",
|
||||||
"diagnosis_domain_expiration_not_found": "Unable to check the expiration date for some domains",
|
"diagnosis_domain_expiration_not_found": "Unable to check the expiration date for some domains",
|
||||||
|
@ -203,7 +200,7 @@
|
||||||
"diagnosis_domain_expiration_warning": "Some domains will expire soon!",
|
"diagnosis_domain_expiration_warning": "Some domains will expire soon!",
|
||||||
"diagnosis_domain_expires_in": "{domain} expires in {days} days.",
|
"diagnosis_domain_expires_in": "{domain} expires in {days} days.",
|
||||||
"diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired!",
|
"diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired!",
|
||||||
"diagnosis_everything_ok": "Everything looks good for {category}!",
|
"diagnosis_everything_ok": "Everything looks OK for {category}!",
|
||||||
"diagnosis_failed": "Failed to fetch diagnosis result for category '{category}': {error}",
|
"diagnosis_failed": "Failed to fetch diagnosis result for category '{category}': {error}",
|
||||||
"diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}",
|
"diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}",
|
||||||
"diagnosis_found_errors": "Found {errors} significant issue(s) related to {category}!",
|
"diagnosis_found_errors": "Found {errors} significant issue(s) related to {category}!",
|
||||||
|
@ -216,7 +213,7 @@
|
||||||
"diagnosis_http_could_not_diagnose_details": "Error: {error}",
|
"diagnosis_http_could_not_diagnose_details": "Error: {error}",
|
||||||
"diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.",
|
"diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.",
|
||||||
"diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?) when using the domain name or global IP. You may be able to improve the situation by having a look at <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a>",
|
"diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?) when using the domain name or global IP. You may be able to improve the situation by having a look at <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a>",
|
||||||
"diagnosis_http_localdomain": "Domain {domain}, with a .local TLD, is not expected to be exposed outside the local network.",
|
"diagnosis_http_special_use_tld": "Domain {domain} is based on a special-use top-level domain (TLD) such as .local or .test and is therefore not expected to be exposed outside the local network.",
|
||||||
"diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.",
|
"diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.",
|
||||||
"diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> and if you're ok, apply the changes with <cmd>yunohost tools regen-conf nginx --force</cmd>.",
|
"diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using <cmd>yunohost tools regen-conf nginx --dry-run --with-diff</cmd> and if you're ok, apply the changes with <cmd>yunohost tools regen-conf nginx --force</cmd>.",
|
||||||
"diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.",
|
"diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.",
|
||||||
|
@ -310,6 +307,7 @@
|
||||||
"domain_deleted": "Domain deleted",
|
"domain_deleted": "Domain deleted",
|
||||||
"domain_deletion_failed": "Unable to delete domain {domain}: {error}",
|
"domain_deletion_failed": "Unable to delete domain {domain}: {error}",
|
||||||
"domain_dns_conf_is_just_a_recommendation": "This command shows you the *recommended* configuration. It does not actually set up the DNS configuration for you. It is your responsability to configure your DNS zone in your registrar according to this recommendation.",
|
"domain_dns_conf_is_just_a_recommendation": "This command shows you the *recommended* configuration. It does not actually set up the DNS configuration for you. It is your responsability to configure your DNS zone in your registrar according to this recommendation.",
|
||||||
|
"domain_dns_conf_special_use_tld": "This domain is based on a special-use top-level domain (TLD) such as .local or .test and is therefore not expected to have actual DNS records.",
|
||||||
"domain_dyndns_already_subscribed": "You have already subscribed to a DynDNS domain",
|
"domain_dyndns_already_subscribed": "You have already subscribed to a DynDNS domain",
|
||||||
"domain_dyndns_root_unknown": "Unknown DynDNS root domain",
|
"domain_dyndns_root_unknown": "Unknown DynDNS root domain",
|
||||||
"domain_exists": "The domain already exists",
|
"domain_exists": "The domain already exists",
|
||||||
|
@ -366,7 +364,6 @@
|
||||||
"extracting": "Extracting...",
|
"extracting": "Extracting...",
|
||||||
"field_invalid": "Invalid field '{}'",
|
"field_invalid": "Invalid field '{}'",
|
||||||
"file_does_not_exist": "The file {path} does not exist.",
|
"file_does_not_exist": "The file {path} does not exist.",
|
||||||
"file_extension_not_accepted": "Refusing file '{path}' because its extension is not among the accepted extensions: {accept}",
|
|
||||||
"firewall_reload_failed": "Could not reload the firewall",
|
"firewall_reload_failed": "Could not reload the firewall",
|
||||||
"firewall_reloaded": "Firewall reloaded",
|
"firewall_reloaded": "Firewall reloaded",
|
||||||
"firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.",
|
"firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.",
|
||||||
|
@ -555,6 +552,7 @@
|
||||||
"migrations_to_be_ran_manually": "Migration {id} has to be run manually. Please go to Tools → Migrations on the webadmin page, or run `yunohost tools migrations run`.",
|
"migrations_to_be_ran_manually": "Migration {id} has to be run manually. Please go to Tools → Migrations on the webadmin page, or run `yunohost tools migrations run`.",
|
||||||
"not_enough_disk_space": "Not enough free space on '{path}'",
|
"not_enough_disk_space": "Not enough free space on '{path}'",
|
||||||
"operation_interrupted": "The operation was manually interrupted?",
|
"operation_interrupted": "The operation was manually interrupted?",
|
||||||
|
"other_available_options": "... and {n} other available options not shown",
|
||||||
"packages_upgrade_failed": "Could not upgrade all the packages",
|
"packages_upgrade_failed": "Could not upgrade all the packages",
|
||||||
"password_listed": "This password is among the most used passwords in the world. Please choose something more unique.",
|
"password_listed": "This password is among the most used passwords in the world. Please choose something more unique.",
|
||||||
"password_too_simple_1": "The password needs to be at least 8 characters long",
|
"password_too_simple_1": "The password needs to be at least 8 characters long",
|
||||||
|
@ -670,7 +668,7 @@
|
||||||
"service_stop_failed": "Unable to stop the service '{service}'\n\nRecent service logs:{logs}",
|
"service_stop_failed": "Unable to stop the service '{service}'\n\nRecent service logs:{logs}",
|
||||||
"service_stopped": "Service '{service}' stopped",
|
"service_stopped": "Service '{service}' stopped",
|
||||||
"service_unknown": "Unknown service '{service}'",
|
"service_unknown": "Unknown service '{service}'",
|
||||||
"show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right no, because the URL for the permission '{permission}' is a regex",
|
"show_tile_cant_be_enabled_for_regex": "You cannot enable 'show_tile' right now, because the URL for the permission '{permission}' is a regex",
|
||||||
"show_tile_cant_be_enabled_for_url_not_defined": "You cannot enable 'show_tile' right now, because you must first define an URL for the permission '{permission}'",
|
"show_tile_cant_be_enabled_for_url_not_defined": "You cannot enable 'show_tile' right now, because you must first define an URL for the permission '{permission}'",
|
||||||
"ssowat_conf_generated": "SSOwat configuration regenerated",
|
"ssowat_conf_generated": "SSOwat configuration regenerated",
|
||||||
"ssowat_conf_updated": "SSOwat configuration updated",
|
"ssowat_conf_updated": "SSOwat configuration updated",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"admin_password_change_failed": "Impossible de changer le mot de passe",
|
"admin_password_change_failed": "Impossible de changer le mot de passe",
|
||||||
"admin_password_changed": "Le mot de passe d'administration a été modifié",
|
"admin_password_changed": "Le mot de passe d'administration a été modifié",
|
||||||
"app_already_installed": "{app} est déjà installé",
|
"app_already_installed": "{app} est déjà installé",
|
||||||
"app_argument_choice_invalid": "Choix invalide pour le paramètre '{name}'. Les valeurs acceptées sont {choices}, au lieu de '{value}'",
|
"app_argument_choice_invalid": "Choisissez une valeur valide pour l'argument '{name}' : '{value}' ne fait pas partie des choix disponibles ({choices})",
|
||||||
"app_argument_invalid": "Valeur invalide pour le paramètre '{name}' : {error}",
|
"app_argument_invalid": "Valeur invalide pour le paramètre '{name}' : {error}",
|
||||||
"app_argument_required": "Le paramètre '{name}' est requis",
|
"app_argument_required": "Le paramètre '{name}' est requis",
|
||||||
"app_extraction_failed": "Impossible d'extraire les fichiers d'installation",
|
"app_extraction_failed": "Impossible d'extraire les fichiers d'installation",
|
||||||
|
@ -431,7 +431,7 @@
|
||||||
"diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment !)",
|
"diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment !)",
|
||||||
"diagnosis_ignored_issues": "(+ {nb_ignored} problème(s) ignoré(s))",
|
"diagnosis_ignored_issues": "(+ {nb_ignored} problème(s) ignoré(s))",
|
||||||
"diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.",
|
"diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.",
|
||||||
"diagnosis_everything_ok": "Tout semble bien pour {category} !",
|
"diagnosis_everything_ok": "Tout semble OK pour {category} !",
|
||||||
"diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}' : {error}",
|
"diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}' : {error}",
|
||||||
"diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !",
|
"diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !",
|
||||||
"diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d'une adresse IPv4.",
|
"diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d'une adresse IPv4.",
|
||||||
|
@ -593,7 +593,7 @@
|
||||||
"diagnosis_package_installed_from_sury": "Des paquets du système devraient être rétrogradé de version",
|
"diagnosis_package_installed_from_sury": "Des paquets du système devraient être rétrogradé de version",
|
||||||
"additional_urls_already_added": "URL supplémentaire '{url}' déjà ajoutée pour la permission '{permission}'",
|
"additional_urls_already_added": "URL supplémentaire '{url}' déjà ajoutée pour la permission '{permission}'",
|
||||||
"unknown_main_domain_path": "Domaine ou chemin inconnu pour '{app}'. Vous devez spécifier un domaine et un chemin pour pouvoir spécifier une URL pour l'autorisation.",
|
"unknown_main_domain_path": "Domaine ou chemin inconnu pour '{app}'. Vous devez spécifier un domaine et un chemin pour pouvoir spécifier une URL pour l'autorisation.",
|
||||||
"show_tile_cant_be_enabled_for_regex": "Vous ne pouvez pas activer 'show_tile' pour le moment, car l'URL de l'autorisation '{permission}' est une expression régulière",
|
"show_tile_cant_be_enabled_for_regex": "Vous ne pouvez pas activer 'show_tile' pour le moment, cela car l'URL de l'autorisation '{permission}' est une expression régulière",
|
||||||
"show_tile_cant_be_enabled_for_url_not_defined": "Vous ne pouvez pas activer 'show_tile' pour le moment, car vous devez d'abord définir une URL pour l'autorisation '{permission}'",
|
"show_tile_cant_be_enabled_for_url_not_defined": "Vous ne pouvez pas activer 'show_tile' pour le moment, car vous devez d'abord définir une URL pour l'autorisation '{permission}'",
|
||||||
"regex_with_only_domain": "Vous ne pouvez pas utiliser une expression régulière pour le domaine, uniquement pour le chemin",
|
"regex_with_only_domain": "Vous ne pouvez pas utiliser une expression régulière pour le domaine, uniquement pour le chemin",
|
||||||
"regex_incompatible_with_tile": "/!\\ Packagers ! La permission '{permission}' a 'show_tile' définie sur 'true' et vous ne pouvez donc pas définir une URL regex comme URL principale",
|
"regex_incompatible_with_tile": "/!\\ Packagers ! La permission '{permission}' a 'show_tile' définie sur 'true' et vous ne pouvez donc pas définir une URL regex comme URL principale",
|
||||||
|
@ -632,7 +632,7 @@
|
||||||
"global_settings_setting_security_webadmin_allowlist": "Adresses IP autorisées à accéder à la webadmin. Elles doivent être séparées par une virgule.",
|
"global_settings_setting_security_webadmin_allowlist": "Adresses IP autorisées à accéder à la webadmin. Elles doivent être séparées par une virgule.",
|
||||||
"global_settings_setting_security_webadmin_allowlist_enabled": "Autoriser seulement certaines IP à accéder à la webadmin.",
|
"global_settings_setting_security_webadmin_allowlist_enabled": "Autoriser seulement certaines IP à accéder à la webadmin.",
|
||||||
"diagnosis_http_localdomain": "Le domaine {domain}, avec un TLD .local, ne devrait pas être exposé en dehors du réseau local.",
|
"diagnosis_http_localdomain": "Le domaine {domain}, avec un TLD .local, ne devrait pas être exposé en dehors du réseau local.",
|
||||||
"diagnosis_dns_specialusedomain": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial et ne devrait donc pas avoir d'enregistrements DNS réels.",
|
"diagnosis_dns_specialusedomain": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial comme .local ou .test et ne devrait donc pas avoir d'enregistrements DNS réels.",
|
||||||
"invalid_password": "Mot de passe incorrect",
|
"invalid_password": "Mot de passe incorrect",
|
||||||
"ldap_server_is_down_restart_it": "Le service LDAP est en panne, essayez de le redémarrer...",
|
"ldap_server_is_down_restart_it": "Le service LDAP est en panne, essayez de le redémarrer...",
|
||||||
"ldap_server_down": "Impossible d'atteindre le serveur LDAP",
|
"ldap_server_down": "Impossible d'atteindre le serveur LDAP",
|
||||||
|
@ -675,5 +675,39 @@
|
||||||
"log_app_config_set": "Appliquer la configuration à l'application '{}'",
|
"log_app_config_set": "Appliquer la configuration à l'application '{}'",
|
||||||
"service_not_reloading_because_conf_broken": "Le service '{name}' n'a pas été rechargé/redémarré car sa configuration est cassée : {errors}",
|
"service_not_reloading_because_conf_broken": "Le service '{name}' n'a pas été rechargé/redémarré car sa configuration est cassée : {errors}",
|
||||||
"app_argument_password_help_keep": "Tapez sur Entrée pour conserver la valeur actuelle",
|
"app_argument_password_help_keep": "Tapez sur Entrée pour conserver la valeur actuelle",
|
||||||
"app_argument_password_help_optional": "Tapez un espace pour vider le mot de passe"
|
"app_argument_password_help_optional": "Tapez un espace pour vider le mot de passe",
|
||||||
|
"domain_registrar_is_not_configured": "Le registrar n'est pas encore configuré pour le domaine {domain}.",
|
||||||
|
"domain_dns_push_not_applicable": "La fonction de configuration DNS automatique n'est pas applicable au domaine {domain}. Vous devez configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns_config.",
|
||||||
|
"domain_dns_registrar_yunohost": "Ce domaine est de type nohost.me / nohost.st / ynh.fr et sa configuration DNS est donc automatiquement gérée par YunoHost sans qu'il n'y ait d'autre configuration à faire. (voir la commande 'yunohost dyndns update')",
|
||||||
|
"domain_dns_registrar_supported": "YunoHost a détecté automatiquement que ce domaine est géré par le registrar **{registrar}**. Si vous le souhaitez, YunoHost configurera automatiquement cette zone DNS, si vous lui fournissez les identifiants API appropriés. Vous pouvez trouver de la documentation sur la façon d'obtenir vos identifiants API sur cette page : https://yunohost.org/registar_api_{registrar}. (Vous pouvez également configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns )",
|
||||||
|
"domain_config_features_disclaimer": "Jusqu'à présent, l'activation/désactivation des fonctionnalités de messagerie ou XMPP n'a d'impact que sur la configuration DNS recommandée et automatique, et non sur les configurations système !",
|
||||||
|
"domain_dns_push_managed_in_parent_domain": "La fonctionnalité de configuration DNS automatique est gérée dans le domaine parent {parent_domain}.",
|
||||||
|
"domain_dns_registrar_managed_in_parent_domain": "Ce domaine est un sous-domaine de {parent_domain_link}. La configuration du registrar DNS doit être gérée dans le panneau de configuration de {parent_domain}.",
|
||||||
|
"domain_dns_registrar_not_supported": "YunoHost n'a pas pu détecter automatiquement le bureau d'enregistrement gérant ce domaine. Vous devez configurer manuellement vos enregistrements DNS en suivant la documentation sur https://yunohost.org/dns.",
|
||||||
|
"domain_dns_registrar_experimental": "Jusqu'à présent, l'interface avec l'API de **{registrar}** n'a pas été correctement testée et revue par la communauté YunoHost. L'assistance est **très expérimentale** - soyez prudent !",
|
||||||
|
"domain_dns_push_failed_to_authenticate": "Échec de l'authentification sur l'API du bureau d'enregistrement pour le domaine « {domain} ». Très probablement les informations d'identification sont incorrectes ? (Erreur : {error})",
|
||||||
|
"domain_dns_push_failed_to_list": "Échec de la liste des enregistrements actuels à l'aide de l'API du registraire : {error}",
|
||||||
|
"domain_dns_push_already_up_to_date": "Dossiers déjà à jour.",
|
||||||
|
"domain_dns_pushing": "Transmission des enregistrements DNS...",
|
||||||
|
"domain_dns_push_record_failed": "Échec de l'enregistrement {action} {type}/{name} : {error}",
|
||||||
|
"domain_dns_push_success": "Enregistrements DNS mis à jour !",
|
||||||
|
"domain_dns_push_failed": "La mise à jour des enregistrements DNS a échoué.",
|
||||||
|
"domain_dns_push_partial_failure": "Enregistrements DNS partiellement mis à jour : certains avertissements/erreurs ont été signalés.",
|
||||||
|
"domain_config_mail_in": "Emails entrants",
|
||||||
|
"domain_config_mail_out": "Emails sortants",
|
||||||
|
"domain_config_xmpp": "Messagerie instantanée (XMPP)",
|
||||||
|
"domain_config_auth_token": "Jeton d'authentification",
|
||||||
|
"domain_config_auth_key": "Clé d'authentification",
|
||||||
|
"domain_config_auth_secret": "Secret d'authentification",
|
||||||
|
"domain_config_api_protocol": "Protocole API",
|
||||||
|
"domain_config_auth_entrypoint": "Point d'entrée API",
|
||||||
|
"domain_config_auth_application_key": "Clé d'application",
|
||||||
|
"domain_config_auth_application_secret": "Clé secrète de l'application",
|
||||||
|
"ldap_attribute_already_exists": "L'attribut LDAP '{attribute}' existe déjà avec la valeur '{value}'",
|
||||||
|
"log_domain_config_set": "Mettre à jour la configuration du domaine '{}'",
|
||||||
|
"log_domain_dns_push": "Pousser les enregistrements DNS pour le domaine '{}'",
|
||||||
|
"diagnosis_http_special_use_tld": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et n'est donc pas censé être exposé en dehors du réseau local.",
|
||||||
|
"domain_dns_conf_special_use_tld": "Ce domaine est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et ne devrait donc pas avoir d'enregistrements DNS réels.",
|
||||||
|
"other_available_options": "... et {n} autres options disponibles non affichées",
|
||||||
|
"domain_config_auth_consumer_key": "Consumer key"
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
"app_argument_required": "Requírese o argumento '{name}'",
|
"app_argument_required": "Requírese o argumento '{name}'",
|
||||||
"app_argument_password_no_default": "Erro ao procesar o argumento do contrasinal '{name}': o argumento do contrasinal non pode ter un valor por defecto por razón de seguridade",
|
"app_argument_password_no_default": "Erro ao procesar o argumento do contrasinal '{name}': o argumento do contrasinal non pode ter un valor por defecto por razón de seguridade",
|
||||||
"app_argument_invalid": "Elixe un valor válido para o argumento '{name}': {error}",
|
"app_argument_invalid": "Elixe un valor válido para o argumento '{name}': {error}",
|
||||||
"app_argument_choice_invalid": "Usa unha destas opcións '{choices}' para o argumento '{name}' no lugar de '{value}'",
|
"app_argument_choice_invalid": "Elixe un valor válido para o argumento '{name}': '{value}' non está entre as opcións dispoñibles ({choices})",
|
||||||
"backup_archive_writing_error": "Non se puideron engadir os ficheiros '{source}' (chamados no arquivo '{dest}' para ser copiados dentro do arquivo comprimido '{archive}'",
|
"backup_archive_writing_error": "Non se puideron engadir os ficheiros '{source}' (chamados no arquivo '{dest}' para ser copiados dentro do arquivo comprimido '{archive}'",
|
||||||
"backup_archive_system_part_not_available": "A parte do sistema '{part}' non está dispoñible nesta copia",
|
"backup_archive_system_part_not_available": "A parte do sistema '{part}' non está dispoñible nesta copia",
|
||||||
"backup_archive_corrupted": "Semella que o arquivo de copia '{archive}' está estragado : {error}",
|
"backup_archive_corrupted": "Semella que o arquivo de copia '{archive}' está estragado : {error}",
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
"backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo",
|
"backup_copying_to_organize_the_archive": "Copiando {size}MB para organizar o arquivo",
|
||||||
"backup_cleaning_failed": "Non se puido baleirar o cartafol temporal para a copia",
|
"backup_cleaning_failed": "Non se puido baleirar o cartafol temporal para a copia",
|
||||||
"backup_cant_mount_uncompress_archive": "Non se puido montar o arquivo sen comprimir porque está protexido contra escritura",
|
"backup_cant_mount_uncompress_archive": "Non se puido montar o arquivo sen comprimir porque está protexido contra escritura",
|
||||||
"backup_ask_for_copying_if_needed": "Queres realizar a copia de apoio utilizando temporalmente {size}MB? (Faise deste xeito porque algúns ficheiros non hai xeito de preparalos usando unha forma máis eficiente).",
|
"backup_ask_for_copying_if_needed": "Queres realizar a copia de apoio utilizando temporalmente {size}MB? (Faise deste xeito porque algúns ficheiros non hai xeito de preparalos usando unha forma máis eficiente.)",
|
||||||
"backup_running_hooks": "Executando os ganchos da copia...",
|
"backup_running_hooks": "Executando os ganchos da copia...",
|
||||||
"backup_permission": "Permiso de copia para {app}",
|
"backup_permission": "Permiso de copia para {app}",
|
||||||
"backup_output_symlink_dir_broken": "O directorio de arquivo '{path}' é unha ligazón simbólica rota. Pode ser que esqueceses re/montar ou conectar o medio de almacenaxe ao que apunta.",
|
"backup_output_symlink_dir_broken": "O directorio de arquivo '{path}' é unha ligazón simbólica rota. Pode ser que esqueceses re/montar ou conectar o medio de almacenaxe ao que apunta.",
|
||||||
|
@ -455,7 +455,7 @@
|
||||||
"migration_0015_modified_files": "Ten en conta que os seguintes ficheiros semella que foron modificados manualmente e poderían ser sobrescritos na actualización: {manually_modified_files}",
|
"migration_0015_modified_files": "Ten en conta que os seguintes ficheiros semella que foron modificados manualmente e poderían ser sobrescritos na actualización: {manually_modified_files}",
|
||||||
"migration_0015_problematic_apps_warning": "Ten en conta que se detectaron as seguintes apps que poderían ser problemáticas. Semella que non foron instaladas usando o catálogo de YunoHost, ou non están marcadas como 'funcionais'. En consecuencia, non se pode garantir que seguirán funcionando após a actualización: {problematic_apps}",
|
"migration_0015_problematic_apps_warning": "Ten en conta que se detectaron as seguintes apps que poderían ser problemáticas. Semella que non foron instaladas usando o catálogo de YunoHost, ou non están marcadas como 'funcionais'. En consecuencia, non se pode garantir que seguirán funcionando após a actualización: {problematic_apps}",
|
||||||
"diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que esté exposto ao exterior da rede local.",
|
"diagnosis_http_localdomain": "O dominio {domain}, cun TLD .local, non é de agardar que esté exposto ao exterior da rede local.",
|
||||||
"diagnosis_dns_specialusedomain": "O dominio {domain} baséase un dominio de nivel alto e uso especial (TLD) polo que non é de agardar que realmente teña rexistros DNS.",
|
"diagnosis_dns_specialusedomain": "O dominio {domain} baséase un dominio de nivel alto e uso especial (TLD) como .local ou .test polo que non é de agardar que realmente teña rexistros DNS.",
|
||||||
"upnp_enabled": "UPnP activado",
|
"upnp_enabled": "UPnP activado",
|
||||||
"upnp_disabled": "UPnP desactivado",
|
"upnp_disabled": "UPnP desactivado",
|
||||||
"permission_creation_failed": "Non se creou o permiso '{permission}': {error}",
|
"permission_creation_failed": "Non se creou o permiso '{permission}': {error}",
|
||||||
|
@ -675,5 +675,39 @@
|
||||||
"config_version_not_supported": "A versión do panel de configuración '{version}' non está soportada.",
|
"config_version_not_supported": "A versión do panel de configuración '{version}' non está soportada.",
|
||||||
"file_extension_not_accepted": "Rexeitouse o ficheiro '{path}' porque a súa extensión non está entre as aceptadas: {accept}",
|
"file_extension_not_accepted": "Rexeitouse o ficheiro '{path}' porque a súa extensión non está entre as aceptadas: {accept}",
|
||||||
"invalid_number_max": "Ten que ser menor de {max}",
|
"invalid_number_max": "Ten que ser menor de {max}",
|
||||||
"service_not_reloading_because_conf_broken": "Non se recargou/reiniciou o servizo '{name}' porque a súa configuración está estragada: {errors}"
|
"service_not_reloading_because_conf_broken": "Non se recargou/reiniciou o servizo '{name}' porque a súa configuración está estragada: {errors}",
|
||||||
|
"diagnosis_http_special_use_tld": "O dominio {domain} baséase nun dominio de alto-nivel (TLD) especial como .local ou .test e por isto non é de agardar que esté exposto fóra da rede local.",
|
||||||
|
"domain_dns_conf_special_use_tld": "Este dominio baséase nun dominio de alto-nivel (TLD) de uso especial como .local ou .test e por isto non é de agardar que teña rexistros DNS asociados.",
|
||||||
|
"domain_dns_registrar_managed_in_parent_domain": "Este dominio é un subdominio de {parent_domain_link}. A configuración DNS debe xestionarse no panel de configuración de {parent_domain}'s.",
|
||||||
|
"domain_dns_registrar_not_supported": "YunoHost non é quen de detectar a rexistradora que xestiona o dominio. Debes configurar manualmente os seus rexistros DNS seguindo a documentación en https://yunohost.org/dns.",
|
||||||
|
"domain_dns_registrar_experimental": "Ata o momento, a interface coa API de **{registrar}** aínda non foi comprobada e revisada pola comunidade YunoHost. O soporte é **moi experimental** - ten coidado!",
|
||||||
|
"domain_dns_push_failed_to_list": "Non se pode mostrar a lista actual de rexistros na API da rexistradora: {error}",
|
||||||
|
"domain_dns_push_already_up_to_date": "Rexistros ao día, nada que facer.",
|
||||||
|
"domain_dns_pushing": "Enviando rexistros DNS...",
|
||||||
|
"domain_dns_push_record_failed": "Fallou {action} do rexistro {type}/{name}: {error}",
|
||||||
|
"domain_dns_push_success": "Rexistros DNS actualizados!",
|
||||||
|
"domain_dns_push_failed": "Fallou completamente a actualización dos rexistros DNS.",
|
||||||
|
"domain_config_features_disclaimer": "Ata o momento, activar/desactivar as funcións de email ou XMPP só ten impacto na configuración automática da configuración DNS, non na configuración do sistema!",
|
||||||
|
"domain_config_mail_in": "Emails entrantes",
|
||||||
|
"domain_config_mail_out": "Emails saíntes",
|
||||||
|
"domain_config_xmpp": "Mensaxería instantánea (XMPP)",
|
||||||
|
"domain_config_auth_secret": "Segreda de autenticación",
|
||||||
|
"domain_config_api_protocol": "Protocolo API",
|
||||||
|
"domain_config_auth_application_key": "Chave da aplicación",
|
||||||
|
"domain_config_auth_application_secret": "Chave segreda da aplicación",
|
||||||
|
"domain_config_auth_consumer_key": "Chave consumidora",
|
||||||
|
"log_domain_dns_push": "Enviar rexistros DNS para o dominio '{}'",
|
||||||
|
"other_available_options": "... e outras {n} opcións dispoñibles non mostradas",
|
||||||
|
"domain_dns_registrar_yunohost": "Este dominio un dos de nohost.me / nohost.st / ynh.fr e a configuración DNS xestionaa directamente YunoHost se máis requisitos. (mira o comando 'yunohost dyndns update')",
|
||||||
|
"domain_dns_registrar_supported": "YunoHost detectou automáticamente que este dominio está xestionado pola rexistradora **{registrar}**. Se queres, YunoHost pode configurar automáticamente as súas zonas DNS, se proporcionas as credenciais de acceso á API. Podes ver a documentación sobre como obter as credenciais da API nesta páxina: https://yunohost.org/registrar_api_{registrar}. (Tamén podes configurar manualmente os rexistros DNS seguindo a documentación en https://yunohost.org/dns )",
|
||||||
|
"domain_dns_push_partial_failure": "Actualización parcial dos rexistros DNS: informouse dalgúns avisos/erros.",
|
||||||
|
"domain_config_auth_token": "Token de autenticación",
|
||||||
|
"domain_config_auth_key": "Chave de autenticación",
|
||||||
|
"domain_config_auth_entrypoint": "Punto de entrada da API",
|
||||||
|
"domain_dns_push_failed_to_authenticate": "Fallou a autenticación na API da rexistradora do dominio '{domain}'. Comprobaches que sexan as credenciais correctas? (Erro: {error})",
|
||||||
|
"domain_registrar_is_not_configured": "A rexistradora non aínda non está configurada para o dominio {domain}.",
|
||||||
|
"domain_dns_push_not_applicable": "A función de rexistro DNS automático non é aplicable ao dominio {domain}. Debes configurar manualmente os teus rexistros DNS seguindo a documentación de https://yunohost.org/dns_config.",
|
||||||
|
"domain_dns_push_managed_in_parent_domain": "A función de rexistro DNS automático está xestionada polo dominio nai {parent_domain}.",
|
||||||
|
"ldap_attribute_already_exists": "Xa existe o atributo LDAP '{attribute}' con valor '{value}'",
|
||||||
|
"log_domain_config_set": "Actualizar configuración para o dominio '{}'"
|
||||||
}
|
}
|
|
@ -109,7 +109,7 @@
|
||||||
"backup_output_directory_forbidden": "Escolha um diretório de saída diferente. Backups não podem ser criados nos subdiretórios /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
|
"backup_output_directory_forbidden": "Escolha um diretório de saída diferente. Backups não podem ser criados nos subdiretórios /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
|
||||||
"app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.",
|
"app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.",
|
||||||
"app_already_up_to_date": "{app} já está atualizado",
|
"app_already_up_to_date": "{app} já está atualizado",
|
||||||
"app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}' em vez de '{value}'",
|
"app_argument_choice_invalid": "Escolha um valor válido para o argumento '{name}' : '{value}' não está entre as opções disponíveis ({choices})",
|
||||||
"app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}",
|
"app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}",
|
||||||
"app_argument_required": "O argumento '{name}' é obrigatório",
|
"app_argument_required": "O argumento '{name}' é obrigatório",
|
||||||
"app_location_unavailable": "Esta url ou não está disponível ou está em conflito com outra(s) aplicação(ões) já instalada(s):\n{apps}",
|
"app_location_unavailable": "Esta url ou não está disponível ou está em conflito com outra(s) aplicação(ões) já instalada(s):\n{apps}",
|
||||||
|
@ -182,7 +182,7 @@
|
||||||
"backup_csv_creation_failed": "Não foi possível criar o arquivo CSV necessário para a restauração",
|
"backup_csv_creation_failed": "Não foi possível criar o arquivo CSV necessário para a restauração",
|
||||||
"backup_csv_addition_failed": "Não foi possível adicionar os arquivos que estarão no backup ao arquivo CSV",
|
"backup_csv_addition_failed": "Não foi possível adicionar os arquivos que estarão no backup ao arquivo CSV",
|
||||||
"backup_create_size_estimation": "O arquivo irá conter cerca de {size} de dados.",
|
"backup_create_size_estimation": "O arquivo irá conter cerca de {size} de dados.",
|
||||||
"backup_couldnt_bind": "Não foi possível vincular {src} ao {dest}",
|
"backup_couldnt_bind": "Não foi possível vincular {src} ao {dest}.",
|
||||||
"certmanager_attempt_to_replace_valid_cert": "Você está tentando sobrescrever um certificado bom e válido para o domínio {domain}! (Use --force para prosseguir mesmo assim)",
|
"certmanager_attempt_to_replace_valid_cert": "Você está tentando sobrescrever um certificado bom e válido para o domínio {domain}! (Use --force para prosseguir mesmo assim)",
|
||||||
"backup_with_no_restore_script_for_app": "A aplicação {app} não tem um script de restauração, você não será capaz de automaticamente restaurar o backup dessa aplicação.",
|
"backup_with_no_restore_script_for_app": "A aplicação {app} não tem um script de restauração, você não será capaz de automaticamente restaurar o backup dessa aplicação.",
|
||||||
"backup_with_no_backup_script_for_app": "A aplicação '{app}' não tem um script de backup. Ignorando.",
|
"backup_with_no_backup_script_for_app": "A aplicação '{app}' não tem um script de backup. Ignorando.",
|
||||||
|
@ -191,5 +191,68 @@
|
||||||
"backup_running_hooks": "Executando os hooks de backup...",
|
"backup_running_hooks": "Executando os hooks de backup...",
|
||||||
"backup_permission": "Permissão de backup para {app}",
|
"backup_permission": "Permissão de backup para {app}",
|
||||||
"backup_output_symlink_dir_broken": "O diretório de seu arquivo '{path}' é um link simbólico quebrado. Talvez você tenha esquecido de re/montar ou conectar o dispositivo de armazenamento para onde o link aponta.",
|
"backup_output_symlink_dir_broken": "O diretório de seu arquivo '{path}' é um link simbólico quebrado. Talvez você tenha esquecido de re/montar ou conectar o dispositivo de armazenamento para onde o link aponta.",
|
||||||
"backup_output_directory_required": "Você deve especificar um diretório de saída para o backup"
|
"backup_output_directory_required": "Você deve especificar um diretório de saída para o backup",
|
||||||
|
"diagnosis_description_apps": "Aplicações",
|
||||||
|
"diagnosis_apps_allgood": "Todos os apps instalados respeitam práticas básicas de empacotamento",
|
||||||
|
"diagnosis_apps_issue": "Um problema foi encontrado para o app {app}",
|
||||||
|
"diagnosis_apps_not_in_app_catalog": "Esta aplicação não está no catálogo de aplicações do YunoHost. Se estava no passado e foi removida, você deve considerar desinstalar este app já que ele não mais receberá atualizações e pode comprometer a integridade e segurança do seu sistema.",
|
||||||
|
"diagnosis_apps_broken": "Esta aplicação está atualmente marcada como quebrada no catálogo de apps do YunoHost. Isto pode ser um problema temporário enquanto os mantenedores consertam o problema. Enquanto isso, atualizar este app está desabilitado.",
|
||||||
|
"diagnosis_apps_bad_quality": "Esta aplicação está atualmente marcada como quebrada no catálogo de apps do YunoHost. Isto pode ser um problema temporário enquanto os mantenedores consertam o problema. Enquanto isso, atualizar este app está desabilitado.",
|
||||||
|
"diagnosis_apps_outdated_ynh_requirement": "A versão instalada deste app requer tão somente yunohost >= 2.x, o que tende a indicar que o app não está atualizado com as práticas de empacotamento recomendadas. Você deve considerar seriamente atualizá-lo.",
|
||||||
|
"diagnosis_apps_deprecated_practices": "A versão instalada deste app usa práticas de empacotamento extremamente velhas que não são mais usadas. Você deve considerar seriamente atualizá-lo.",
|
||||||
|
"certmanager_domain_http_not_working": "O domínio {domain} não parece estar acessível por HTTP. Por favor cheque a categoria 'Web' no diagnóstico para mais informações. (Se você sabe o que está fazendo, use '--no-checks' para desativar estas checagens.)",
|
||||||
|
"diagnosis_description_regenconf": "Configurações do sistema",
|
||||||
|
"diagnosis_description_services": "Cheque de status dos serviços",
|
||||||
|
"diagnosis_basesystem_hardware": "A arquitetura hardware do servidor é {virt} {arch}",
|
||||||
|
"diagnosis_description_web": "Web",
|
||||||
|
"diagnosis_basesystem_ynh_single_version": "Versão {package}: {version} ({repo})",
|
||||||
|
"diagnosis_basesystem_ynh_main_version": "O servidor está rodando YunoHost {main_version} ({repo})",
|
||||||
|
"app_config_unable_to_apply": "Falha ao aplicar valores do painel de configuração.",
|
||||||
|
"app_config_unable_to_read": "Falha ao ler valores do painel de configuração.",
|
||||||
|
"config_apply_failed": "Aplicar as novas configuração falhou: {error}",
|
||||||
|
"config_cant_set_value_on_section": "Você não pode setar um único valor na seção de configuração inteira.",
|
||||||
|
"config_validate_time": "Deve ser um horário válido como HH:MM",
|
||||||
|
"config_validate_url": "Deve ser uma URL válida",
|
||||||
|
"config_version_not_supported": "Versões do painel de configuração '{version}' não são suportadas.",
|
||||||
|
"danger": "Perigo:",
|
||||||
|
"diagnosis_basesystem_ynh_inconsistent_versions": "Você está executando versões inconsistentes dos pacotes YunoHost... provavelmente por causa de uma atualização parcial ou que falhou.",
|
||||||
|
"diagnosis_description_basesystem": "Sistema base",
|
||||||
|
"certmanager_cert_signing_failed": "Não foi possível assinar o novo certificado",
|
||||||
|
"certmanager_unable_to_parse_self_CA_name": "Não foi possível processar nome da autoridade de auto-assinatura (arquivo: {file})",
|
||||||
|
"confirm_app_install_warning": "Aviso: Pode ser que essa aplicação funcione, mas ela não está bem integrada ao YunoHost. Algumas funcionalidades como single sign-on e backup/restauração podem não estar disponíveis. Instalar mesmo assim? [{answers}] ",
|
||||||
|
"config_forbidden_keyword": "A palavra chave '{keyword}' é reservada, você não pode criar ou usar um painel de configuração com uma pergunta com esse id.",
|
||||||
|
"config_no_panel": "Painel de configuração não encontrado.",
|
||||||
|
"config_unknown_filter_key": "A chave de filtro '{filter_key}' está incorreta.",
|
||||||
|
"config_validate_color": "Deve ser uma cor RGB hexadecimal válida",
|
||||||
|
"config_validate_date": "Deve ser uma data válida como no formato AAAA-MM-DD",
|
||||||
|
"config_validate_email": "Deve ser um email válido",
|
||||||
|
"diagnosis_basesystem_kernel": "O servidor está rodando Linux kernel {kernel_version}",
|
||||||
|
"diagnosis_cache_still_valid": "(O cache para a categoria de diagnóstico {category} ainda é valido. Não será diagnosticada novamente ainda)",
|
||||||
|
"diagnosis_cant_run_because_of_dep": "Impossível fazer diagnóstico para {category} enquanto ainda existem problemas importantes relacionados a {dep}.",
|
||||||
|
"diagnosis_diskusage_low": "Unidade de armazenamento <code>{mountpoint}</code> (no dispositivo <code>{device}</code>_) tem somente {free} ({free_percent}%) de espaço restante (de {total}). Tenha cuidado.",
|
||||||
|
"diagnosis_description_ip": "Conectividade internet",
|
||||||
|
"diagnosis_description_dnsrecords": "Registros DNS",
|
||||||
|
"diagnosis_description_mail": "Email",
|
||||||
|
"certmanager_domain_not_diagnosed_yet": "Ainda não há resultado de diagnóstico para o domínio {domain}. Por favor re-execute um diagnóstico para as categorias 'Registros DNS' e 'Web' na seção de diagnósticos para checar se o domínio está pronto para o Let's Encrypt. (Ou, se você souber o que está fazendo, use '--no-checks' para desativar estas checagens.)",
|
||||||
|
"diagnosis_basesystem_host": "O Servidor está rodando Debian {debian_version}",
|
||||||
|
"diagnosis_description_systemresources": "Recursos do sistema",
|
||||||
|
"certmanager_acme_not_configured_for_domain": "O challenge ACME não pode ser realizado para {domain} porque o código correspondente na configuração do nginx está ausente... Por favor tenha certeza de que sua configuração do nginx está atualizada executando o comando `yunohost tools regen-conf nginx --dry-run --with-diff`.",
|
||||||
|
"certmanager_attempt_to_renew_nonLE_cert": "O certificado para o domínio '{domain}' não foi emitido pelo Let's Encrypt. Não é possível renová-lo automaticamente!",
|
||||||
|
"certmanager_attempt_to_renew_valid_cert": "O certificado para o domínio '{domain}' não esta prestes a expirar! (Você pode usar --force se saber o que está fazendo)",
|
||||||
|
"certmanager_cannot_read_cert": "Algo de errado aconteceu ao tentar abrir o atual certificado para o domínio {domain} (arquivo: {file}), motivo: {reason}",
|
||||||
|
"certmanager_cert_install_success": "Certificado Let's Encrypt foi instalado para o domínio '{domain}'",
|
||||||
|
"certmanager_cert_install_success_selfsigned": "Certificado autoassinado foi instalado para o domínio '{domain}'",
|
||||||
|
"certmanager_certificate_fetching_or_enabling_failed": "Tentativa de usar o novo certificado para o domínio {domain} não funcionou...",
|
||||||
|
"certmanager_domain_cert_not_selfsigned": "O certificado para o domínio {domain} não é autoassinado. Você tem certeza que quer substituí-lo? (Use '--force' para fazê-lo)",
|
||||||
|
"certmanager_domain_dns_ip_differs_from_public_ip": "O registro de DNS para o domínio '{domain}' é diferente do IP deste servidor. Por favor cheque a categoria 'Registros DNS' (básico) no diagnóstico para mais informações. Se você modificou recentemente o registro 'A', espere um tempo para ele se propagar (alguns serviços de checagem de propagação de DNS estão disponíveis online). (Se você sabe o que está fazendo, use '--no-checks' para desativar estas checagens.)",
|
||||||
|
"certmanager_hit_rate_limit": "Foram emitidos certificados demais para este conjunto de domínios {domain} recentemente. Por favor tente novamente mais tarde. Veja https://letsencrypt.org/docs/rate-limits/ para mais detalhes",
|
||||||
|
"certmanager_no_cert_file": "Não foi possível ler o arquivo de certificado para o domínio {domain} (arquivo: {file})",
|
||||||
|
"certmanager_self_ca_conf_file_not_found": "Não foi possível encontrar o arquivo de configuração para a autoridade de auto-assinatura (arquivo: {file})",
|
||||||
|
"confirm_app_install_danger": "ATENÇÃO! Sabe-se que esta aplicação ainda é experimental (isso se não que explicitamente não funciona)! Você provavelmente NÃO deve instalar ela a não ser que você saiba o que você está fazendo. NENHUM SUPORTE será fornecido se esta aplicação não funcionar ou quebrar o seu sistema... Se você está disposto a tomar esse rico de toda forma, digite '{answers}'",
|
||||||
|
"confirm_app_install_thirdparty": "ATENÇÃO! Essa aplicação não faz parte do catálogo do YunoHost. Instalar aplicações de terceiros pode comprometer a integridade e segurança do seu sistema. Você provavelmente NÃO deve instalá-la a não ser que você saiba o que você está fazendo. NENHUM SUPORTE será fornecido se este app não funcionar ou quebrar seu sistema... Se você está disposto a tomar este risco de toda forma, digite '{answers}'",
|
||||||
|
"diagnosis_description_ports": "Exposição de portas",
|
||||||
|
"diagnosis_basesystem_hardware_model": "O modelo do servidor é {model}",
|
||||||
|
"diagnosis_backports_in_sources_list": "Parece que o apt (o gerenciador de pacotes) está configurado para usar o repositório backport. A não ser que você saiba o que você esteá fazendo, desencorajamos fortemente a instalação de pacotes de backports porque é provável que crie instabilidades ou conflitos no seu sistema.",
|
||||||
|
"certmanager_cert_renew_success": "Certificado Let's Encrypt renovado para o domínio '{domain}'",
|
||||||
|
"certmanager_warning_subdomain_dns_record": "O subdomínio '{subdomain}' não resolve para o mesmo IP que '{domain}'. Algumas funcionalidades não estarão disponíveis até que você conserte isto e regenere o certificado."
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
"app_argument_required": "Аргумент '{name}' необхідний",
|
"app_argument_required": "Аргумент '{name}' необхідний",
|
||||||
"app_argument_password_no_default": "Помилка під час розбору аргументу пароля '{name}': аргумент пароля не може мати типове значення з причин безпеки",
|
"app_argument_password_no_default": "Помилка під час розбору аргументу пароля '{name}': аргумент пароля не може мати типове значення з причин безпеки",
|
||||||
"app_argument_invalid": "Виберіть правильне значення для аргументу '{name}': {error}",
|
"app_argument_invalid": "Виберіть правильне значення для аргументу '{name}': {error}",
|
||||||
"app_argument_choice_invalid": "Використовуйте один з цих варіантів '{choices}' для аргументу '{name}' замість '{value}'",
|
"app_argument_choice_invalid": "Виберіть дійсне значення для аргументу '{name}': '{value}' не є серед доступних варіантів ({choices})",
|
||||||
"app_already_up_to_date": "{app} має найостаннішу версію",
|
"app_already_up_to_date": "{app} має найостаннішу версію",
|
||||||
"app_already_installed_cant_change_url": "Цей застосунок уже встановлено. URL-адреса не може бути змінена тільки цією функцією. Перевірте в `app changeurl`, якщо вона доступна.",
|
"app_already_installed_cant_change_url": "Цей застосунок уже встановлено. URL-адреса не може бути змінена тільки цією функцією. Перевірте в `app changeurl`, якщо вона доступна.",
|
||||||
"app_already_installed": "{app} уже встановлено",
|
"app_already_installed": "{app} уже встановлено",
|
||||||
|
@ -482,7 +482,7 @@
|
||||||
"diagnosis_domain_expiration_not_found_details": "Відомості WHOIS для домену {domain} не містять даних про строк дії?",
|
"diagnosis_domain_expiration_not_found_details": "Відомості WHOIS для домену {domain} не містять даних про строк дії?",
|
||||||
"diagnosis_domain_not_found_details": "Домен {domain} не існує в базі даних WHOIS або строк його дії сплив!",
|
"diagnosis_domain_not_found_details": "Домен {domain} не існує в базі даних WHOIS або строк його дії сплив!",
|
||||||
"diagnosis_domain_expiration_not_found": "Неможливо перевірити строк дії деяких доменів",
|
"diagnosis_domain_expiration_not_found": "Неможливо перевірити строк дії деяких доменів",
|
||||||
"diagnosis_dns_specialusedomain": "Домен {domain} заснований на домені верхнього рівня спеціального призначення (TLD) і тому не очікується, що у нього будуть актуальні записи DNS.",
|
"diagnosis_dns_specialusedomain": "Домен {domain} заснований на домені верхнього рівня спеціального призначення (TLD) такого як .local або .test і тому не очікується, що у нього будуть актуальні записи DNS.",
|
||||||
"diagnosis_dns_try_dyndns_update_force": "Конфігурація DNS цього домену повинна автоматично управлятися YunoHost. Якщо це не так, ви можете спробувати примусово оновити її за допомогою команди <cmd>yunohost dyndns update --force</cmd>.",
|
"diagnosis_dns_try_dyndns_update_force": "Конфігурація DNS цього домену повинна автоматично управлятися YunoHost. Якщо це не так, ви можете спробувати примусово оновити її за допомогою команди <cmd>yunohost dyndns update --force</cmd>.",
|
||||||
"diagnosis_dns_point_to_doc": "Якщо вам потрібна допомога з налаштування DNS-записів, зверніться до документації на сайті <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a>.",
|
"diagnosis_dns_point_to_doc": "Якщо вам потрібна допомога з налаштування DNS-записів, зверніться до документації на сайті <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a>.",
|
||||||
"diagnosis_dns_discrepancy": "Наступний запис DNS, схоже, не відповідає рекомендованій конфігурації: <br>Тип: <code>{type}</code><br>Назва: <code>{name}</code><br>Поточне значення: <code>{current}</code><br>Очікуване значення: <code>{value}</code>",
|
"diagnosis_dns_discrepancy": "Наступний запис DNS, схоже, не відповідає рекомендованій конфігурації: <br>Тип: <code>{type}</code><br>Назва: <code>{name}</code><br>Поточне значення: <code>{current}</code><br>Очікуване значення: <code>{value}</code>",
|
||||||
|
@ -504,7 +504,7 @@
|
||||||
"diagnosis_ip_connected_ipv4": "Сервер під'єднаний до Інтернету через IPv4!",
|
"diagnosis_ip_connected_ipv4": "Сервер під'єднаний до Інтернету через IPv4!",
|
||||||
"diagnosis_no_cache": "Для категорії «{category}» ще немає кеша діагностики",
|
"diagnosis_no_cache": "Для категорії «{category}» ще немає кеша діагностики",
|
||||||
"diagnosis_failed": "Не вдалося отримати результат діагностики для категорії '{category}': {error}",
|
"diagnosis_failed": "Не вдалося отримати результат діагностики для категорії '{category}': {error}",
|
||||||
"diagnosis_everything_ok": "Усе виглядає добре для {category}!",
|
"diagnosis_everything_ok": "Здається, для категорії '{category}' все справно!",
|
||||||
"diagnosis_found_warnings": "Знайдено {warnings} пунктів, які можна поліпшити для {category}.",
|
"diagnosis_found_warnings": "Знайдено {warnings} пунктів, які можна поліпшити для {category}.",
|
||||||
"diagnosis_found_errors_and_warnings": "Знайдено {errors} істотний (і) питання (и) (і {warnings} попередження (я)), що відносяться до {category}!",
|
"diagnosis_found_errors_and_warnings": "Знайдено {errors} істотний (і) питання (и) (і {warnings} попередження (я)), що відносяться до {category}!",
|
||||||
"diagnosis_found_errors": "Знайдена {errors} важлива проблема (і), пов'язана з {category}!",
|
"diagnosis_found_errors": "Знайдена {errors} важлива проблема (і), пов'язана з {category}!",
|
||||||
|
@ -675,5 +675,39 @@
|
||||||
"log_app_config_set": "Застосувати конфігурацію до застосунку '{}'",
|
"log_app_config_set": "Застосувати конфігурацію до застосунку '{}'",
|
||||||
"service_not_reloading_because_conf_broken": "Неможливо перезавантажити/перезапустити службу '{name}', тому що її конфігурацію порушено: {errors}",
|
"service_not_reloading_because_conf_broken": "Неможливо перезавантажити/перезапустити службу '{name}', тому що її конфігурацію порушено: {errors}",
|
||||||
"app_argument_password_help_optional": "Введіть один пробіл, щоб очистити пароль",
|
"app_argument_password_help_optional": "Введіть один пробіл, щоб очистити пароль",
|
||||||
"app_argument_password_help_keep": "Натисніть Enter, щоб зберегти поточне значення"
|
"app_argument_password_help_keep": "Натисніть Enter, щоб зберегти поточне значення",
|
||||||
|
"domain_registrar_is_not_configured": "Реєстратор ще не конфігуровано для домену {domain}.",
|
||||||
|
"domain_dns_push_not_applicable": "Функція автоматичної конфігурації DNS не застосовується до домену {domain}. Вам слід вручну конфігурувати записи DNS відповідно до документації за адресою https://yunohost.org/dns_config.",
|
||||||
|
"domain_dns_registrar_not_supported": "YunoHost не зміг автоматично виявити реєстратора, який обробляє цей домен. Вам слід вручну конфігурувати записи DNS відповідно до документації за адресою https://yunohost.org/dns.",
|
||||||
|
"diagnosis_http_special_use_tld": "Домен {domain} базується на спеціальному домені верхнього рівня (TLD), такому як .local або .test, і тому не очікується, що він буде відкритий за межами локальної мережі.",
|
||||||
|
"domain_dns_push_managed_in_parent_domain": "Функцією автоконфігурації DNS керує батьківський домен {parent_domain}.",
|
||||||
|
"domain_dns_registrar_managed_in_parent_domain": "Цей домен є піддоменом {parent_domain_link}. Конфігурацією реєстратора DNS слід керувати на панелі конфігурації {parent_domain}.",
|
||||||
|
"domain_dns_registrar_yunohost": "Цей домен є nohost.me/nohost.st/ynh.fr, тому його конфігурація DNS автоматично обробляється YunoHost без будь-якої подальшої конфігурації. (див. команду 'yunohost dyndns update')",
|
||||||
|
"domain_dns_conf_special_use_tld": "Цей домен засновано на спеціальному домені верхнього рівня (TLD), такому як .local або .test, і тому не очікується, що він матиме актуальні записи DNS.",
|
||||||
|
"domain_dns_registrar_supported": "YunoHost автоматично визначив, що цей домен обслуговується реєстратором **{registrar}**. Якщо ви хочете, YunoHost автоматично налаштує цю DNS-зону, якщо ви надасте йому відповідні облікові дані API. Ви можете знайти документацію про те, як отримати реєстраційні дані API на цій сторінці: https://yunohost.org/registar_api_{registrar}. (Ви також можете вручну налаштувати свої DNS-записи, дотримуючись документації на https://yunohost.org/dns)",
|
||||||
|
"domain_dns_registrar_experimental": "Поки що інтерфейс з API **{registrar}** не був належним чином протестований і перевірений спільнотою YunoHost. Підтримка є **дуже експериментальною** - будьте обережні!",
|
||||||
|
"domain_dns_push_success": "Записи DNS оновлено!",
|
||||||
|
"domain_dns_push_failed": "Оновлення записів DNS зазнало невдачі.",
|
||||||
|
"domain_dns_push_partial_failure": "DNS-записи частково оновлено: повідомлялося про деякі попередження/помилки.",
|
||||||
|
"domain_config_mail_in": "Вхідні електронні листи",
|
||||||
|
"domain_config_mail_out": "Вихідні електронні листи",
|
||||||
|
"domain_config_auth_token": "Токен автентифікації",
|
||||||
|
"domain_config_auth_entrypoint": "Точка входу API",
|
||||||
|
"domain_config_auth_consumer_key": "Ключ споживача",
|
||||||
|
"domain_dns_push_failed_to_authenticate": "Неможливо пройти автентифікацію на API реєстратора для домену '{domain}'. Ймовірно, облікові дані недійсні? (Помилка: {error})",
|
||||||
|
"domain_dns_push_failed_to_list": "Не вдалося скласти список поточних записів за допомогою API реєстратора: {error}",
|
||||||
|
"domain_dns_push_record_failed": "Не вдалося виконати дію {action} запису {type}/{name} : {error}",
|
||||||
|
"domain_config_features_disclaimer": "Поки що вмикання/вимикання функцій пошти або XMPP впливає тільки на рекомендовану та автоконфігурацію DNS, але не на конфігурацію системи!",
|
||||||
|
"domain_config_xmpp": "Миттєвий обмін повідомленнями (XMPP)",
|
||||||
|
"domain_config_auth_key": "Ключ автентифікації",
|
||||||
|
"domain_config_auth_secret": "Секрет автентифікації",
|
||||||
|
"domain_config_api_protocol": "API-протокол",
|
||||||
|
"domain_config_auth_application_key": "Ключ застосунку",
|
||||||
|
"domain_config_auth_application_secret": "Таємний ключ застосунку",
|
||||||
|
"log_domain_config_set": "Оновлення конфігурації для домену '{}'",
|
||||||
|
"log_domain_dns_push": "Передавання записів DNS для домену '{}'",
|
||||||
|
"other_available_options": "...і {n} інших доступних опцій, які не показано",
|
||||||
|
"domain_dns_pushing": "Передання записів DNS...",
|
||||||
|
"ldap_attribute_already_exists": "Атрибут LDAP '{attribute}' вже існує зі значенням '{value}'",
|
||||||
|
"domain_dns_push_already_up_to_date": "Записи вже оновлені, нічого не потрібно робити."
|
||||||
}
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
[report]
|
|
||||||
omit=tests/*,vendor/*,/usr/lib/moulinette/yunohost/
|
|
1255
src/yunohost/app.py
1255
src/yunohost/app.py
File diff suppressed because it is too large
Load diff
255
src/yunohost/app_catalog.py
Normal file
255
src/yunohost/app_catalog.py
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from moulinette import m18n
|
||||||
|
from moulinette.utils.log import getActionLogger
|
||||||
|
from moulinette.utils.network import download_json
|
||||||
|
from moulinette.utils.filesystem import (
|
||||||
|
read_json,
|
||||||
|
read_yaml,
|
||||||
|
write_to_json,
|
||||||
|
write_to_yaml,
|
||||||
|
mkdir,
|
||||||
|
)
|
||||||
|
|
||||||
|
from yunohost.utils.i18n import _value_for_locale
|
||||||
|
from yunohost.utils.error import YunohostError
|
||||||
|
|
||||||
|
logger = getActionLogger("yunohost.app_catalog")
|
||||||
|
|
||||||
|
APPS_CATALOG_CACHE = "/var/cache/yunohost/repo"
|
||||||
|
APPS_CATALOG_CONF = "/etc/yunohost/apps_catalog.yml"
|
||||||
|
APPS_CATALOG_API_VERSION = 2
|
||||||
|
APPS_CATALOG_DEFAULT_URL = "https://app.yunohost.org/default"
|
||||||
|
|
||||||
|
|
||||||
|
# Old legacy function...
|
||||||
|
def app_fetchlist():
|
||||||
|
logger.warning(
|
||||||
|
"'yunohost app fetchlist' is deprecated. Please use 'yunohost tools update --apps' instead"
|
||||||
|
)
|
||||||
|
from yunohost.tools import tools_update
|
||||||
|
|
||||||
|
tools_update(target="apps")
|
||||||
|
|
||||||
|
|
||||||
|
def app_catalog(full=False, with_categories=False):
|
||||||
|
"""
|
||||||
|
Return a dict of apps available to installation from Yunohost's app catalog
|
||||||
|
"""
|
||||||
|
|
||||||
|
from yunohost.app import _installed_apps, _set_default_ask_questions
|
||||||
|
|
||||||
|
# Get app list from catalog cache
|
||||||
|
catalog = _load_apps_catalog()
|
||||||
|
installed_apps = set(_installed_apps())
|
||||||
|
|
||||||
|
# Trim info for apps if not using --full
|
||||||
|
for app, infos in catalog["apps"].items():
|
||||||
|
infos["installed"] = app in installed_apps
|
||||||
|
|
||||||
|
infos["manifest"]["description"] = _value_for_locale(
|
||||||
|
infos["manifest"]["description"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if not full:
|
||||||
|
catalog["apps"][app] = {
|
||||||
|
"description": infos["manifest"]["description"],
|
||||||
|
"level": infos["level"],
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
infos["manifest"]["arguments"] = _set_default_ask_questions(
|
||||||
|
infos["manifest"].get("arguments", {})
|
||||||
|
)
|
||||||
|
|
||||||
|
# Trim info for categories if not using --full
|
||||||
|
for category in catalog["categories"]:
|
||||||
|
category["title"] = _value_for_locale(category["title"])
|
||||||
|
category["description"] = _value_for_locale(category["description"])
|
||||||
|
for subtags in category.get("subtags", []):
|
||||||
|
subtags["title"] = _value_for_locale(subtags["title"])
|
||||||
|
|
||||||
|
if not full:
|
||||||
|
catalog["categories"] = [
|
||||||
|
{"id": c["id"], "description": c["description"]}
|
||||||
|
for c in catalog["categories"]
|
||||||
|
]
|
||||||
|
|
||||||
|
if not with_categories:
|
||||||
|
return {"apps": catalog["apps"]}
|
||||||
|
else:
|
||||||
|
return {"apps": catalog["apps"], "categories": catalog["categories"]}
|
||||||
|
|
||||||
|
|
||||||
|
def app_search(string):
|
||||||
|
"""
|
||||||
|
Return a dict of apps whose description or name match the search string
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Retrieve a simple dict listing all apps
|
||||||
|
catalog_of_apps = app_catalog()
|
||||||
|
|
||||||
|
# Selecting apps according to a match in app name or description
|
||||||
|
matching_apps = {"apps": {}}
|
||||||
|
for app in catalog_of_apps["apps"].items():
|
||||||
|
if re.search(string, app[0], flags=re.IGNORECASE) or re.search(
|
||||||
|
string, app[1]["description"], flags=re.IGNORECASE
|
||||||
|
):
|
||||||
|
matching_apps["apps"][app[0]] = app[1]
|
||||||
|
|
||||||
|
return matching_apps
|
||||||
|
|
||||||
|
|
||||||
|
def _initialize_apps_catalog_system():
|
||||||
|
"""
|
||||||
|
This function is meant to intialize the apps_catalog system with YunoHost's default app catalog.
|
||||||
|
"""
|
||||||
|
|
||||||
|
default_apps_catalog_list = [{"id": "default", "url": APPS_CATALOG_DEFAULT_URL}]
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.debug(
|
||||||
|
"Initializing apps catalog system with YunoHost's default app list"
|
||||||
|
)
|
||||||
|
write_to_yaml(APPS_CATALOG_CONF, default_apps_catalog_list)
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError(
|
||||||
|
"Could not initialize the apps catalog system... : %s" % str(e)
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.success(m18n.n("apps_catalog_init_success"))
|
||||||
|
|
||||||
|
|
||||||
|
def _read_apps_catalog_list():
|
||||||
|
"""
|
||||||
|
Read the json corresponding to the list of apps catalogs
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
list_ = read_yaml(APPS_CATALOG_CONF)
|
||||||
|
# Support the case where file exists but is empty
|
||||||
|
# by returning [] if list_ is None
|
||||||
|
return list_ if list_ else []
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError("Could not read the apps_catalog list ... : %s" % str(e))
|
||||||
|
|
||||||
|
|
||||||
|
def _actual_apps_catalog_api_url(base_url):
|
||||||
|
|
||||||
|
return "{base_url}/v{version}/apps.json".format(
|
||||||
|
base_url=base_url, version=APPS_CATALOG_API_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _update_apps_catalog():
|
||||||
|
"""
|
||||||
|
Fetches the json for each apps_catalog and update the cache
|
||||||
|
|
||||||
|
apps_catalog_list is for example :
|
||||||
|
[ {"id": "default", "url": "https://app.yunohost.org/default/"} ]
|
||||||
|
|
||||||
|
Then for each apps_catalog, the actual json URL to be fetched is like :
|
||||||
|
https://app.yunohost.org/default/vX/apps.json
|
||||||
|
|
||||||
|
And store it in :
|
||||||
|
/var/cache/yunohost/repo/default.json
|
||||||
|
"""
|
||||||
|
|
||||||
|
apps_catalog_list = _read_apps_catalog_list()
|
||||||
|
|
||||||
|
logger.info(m18n.n("apps_catalog_updating"))
|
||||||
|
|
||||||
|
# Create cache folder if needed
|
||||||
|
if not os.path.exists(APPS_CATALOG_CACHE):
|
||||||
|
logger.debug("Initialize folder for apps catalog cache")
|
||||||
|
mkdir(APPS_CATALOG_CACHE, mode=0o750, parents=True, uid="root")
|
||||||
|
|
||||||
|
for apps_catalog in apps_catalog_list:
|
||||||
|
apps_catalog_id = apps_catalog["id"]
|
||||||
|
actual_api_url = _actual_apps_catalog_api_url(apps_catalog["url"])
|
||||||
|
|
||||||
|
# Fetch the json
|
||||||
|
try:
|
||||||
|
apps_catalog_content = download_json(actual_api_url)
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError(
|
||||||
|
"apps_catalog_failed_to_download",
|
||||||
|
apps_catalog=apps_catalog_id,
|
||||||
|
error=str(e),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remember the apps_catalog api version for later
|
||||||
|
apps_catalog_content["from_api_version"] = APPS_CATALOG_API_VERSION
|
||||||
|
|
||||||
|
# Save the apps_catalog data in the cache
|
||||||
|
cache_file = "{cache_folder}/{list}.json".format(
|
||||||
|
cache_folder=APPS_CATALOG_CACHE, list=apps_catalog_id
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
write_to_json(cache_file, apps_catalog_content)
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError(
|
||||||
|
"Unable to write cache data for %s apps_catalog : %s"
|
||||||
|
% (apps_catalog_id, str(e))
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.success(m18n.n("apps_catalog_update_success"))
|
||||||
|
|
||||||
|
|
||||||
|
def _load_apps_catalog():
|
||||||
|
"""
|
||||||
|
Read all the apps catalog cache files and build a single dict (merged_catalog)
|
||||||
|
corresponding to all known apps and categories
|
||||||
|
"""
|
||||||
|
|
||||||
|
merged_catalog = {"apps": {}, "categories": []}
|
||||||
|
|
||||||
|
for apps_catalog_id in [L["id"] for L in _read_apps_catalog_list()]:
|
||||||
|
|
||||||
|
# Let's load the json from cache for this catalog
|
||||||
|
cache_file = "{cache_folder}/{list}.json".format(
|
||||||
|
cache_folder=APPS_CATALOG_CACHE, list=apps_catalog_id
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
apps_catalog_content = (
|
||||||
|
read_json(cache_file) if os.path.exists(cache_file) else None
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError(
|
||||||
|
"Unable to read cache for apps_catalog %s : %s" % (cache_file, e),
|
||||||
|
raw_msg=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that the version of the data matches version ....
|
||||||
|
# ... otherwise it means we updated yunohost in the meantime
|
||||||
|
# and need to update the cache for everything to be consistent
|
||||||
|
if (
|
||||||
|
not apps_catalog_content
|
||||||
|
or apps_catalog_content.get("from_api_version") != APPS_CATALOG_API_VERSION
|
||||||
|
):
|
||||||
|
logger.info(m18n.n("apps_catalog_obsolete_cache"))
|
||||||
|
_update_apps_catalog()
|
||||||
|
apps_catalog_content = read_json(cache_file)
|
||||||
|
|
||||||
|
del apps_catalog_content["from_api_version"]
|
||||||
|
|
||||||
|
# Add apps from this catalog to the output
|
||||||
|
for app, info in apps_catalog_content["apps"].items():
|
||||||
|
|
||||||
|
# (N.B. : there's a small edge case where multiple apps catalog could be listing the same apps ...
|
||||||
|
# in which case we keep only the first one found)
|
||||||
|
if app in merged_catalog["apps"]:
|
||||||
|
logger.warning(
|
||||||
|
"Duplicate app %s found between apps catalog %s and %s"
|
||||||
|
% (app, apps_catalog_id, merged_catalog["apps"][app]["repository"])
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
info["repository"] = apps_catalog_id
|
||||||
|
merged_catalog["apps"][app] = info
|
||||||
|
|
||||||
|
# Annnnd categories
|
||||||
|
merged_catalog["categories"] += apps_catalog_content["categories"]
|
||||||
|
|
||||||
|
return merged_catalog
|
|
@ -49,10 +49,6 @@ from yunohost.app import (
|
||||||
app_info,
|
app_info,
|
||||||
_is_installed,
|
_is_installed,
|
||||||
_make_environment_for_app_script,
|
_make_environment_for_app_script,
|
||||||
_patch_legacy_helpers,
|
|
||||||
_patch_legacy_php_versions,
|
|
||||||
_patch_legacy_php_versions_in_settings,
|
|
||||||
LEGACY_PHP_VERSION_REPLACEMENTS,
|
|
||||||
_make_tmp_workdir_for_app,
|
_make_tmp_workdir_for_app,
|
||||||
)
|
)
|
||||||
from yunohost.hook import (
|
from yunohost.hook import (
|
||||||
|
@ -1190,6 +1186,7 @@ class RestoreManager:
|
||||||
"""
|
"""
|
||||||
Apply dirty patch to redirect php5 and php7.0 files to php7.3
|
Apply dirty patch to redirect php5 and php7.0 files to php7.3
|
||||||
"""
|
"""
|
||||||
|
from yunohost.utils.legacy import LEGACY_PHP_VERSION_REPLACEMENTS
|
||||||
|
|
||||||
backup_csv = os.path.join(self.work_dir, "backup.csv")
|
backup_csv = os.path.join(self.work_dir, "backup.csv")
|
||||||
|
|
||||||
|
@ -1351,6 +1348,11 @@ class RestoreManager:
|
||||||
app_instance_name -- (string) The app name to restore (no app with this
|
app_instance_name -- (string) The app name to restore (no app with this
|
||||||
name should be already install)
|
name should be already install)
|
||||||
"""
|
"""
|
||||||
|
from yunohost.utils.legacy import (
|
||||||
|
_patch_legacy_php_versions,
|
||||||
|
_patch_legacy_php_versions_in_settings,
|
||||||
|
_patch_legacy_helpers,
|
||||||
|
)
|
||||||
from yunohost.user import user_group_list
|
from yunohost.user import user_group_list
|
||||||
from yunohost.permission import (
|
from yunohost.permission import (
|
||||||
permission_create,
|
permission_create,
|
||||||
|
@ -1485,7 +1487,11 @@ class RestoreManager:
|
||||||
logger.debug(m18n.n("restore_running_app_script", app=app_instance_name))
|
logger.debug(m18n.n("restore_running_app_script", app=app_instance_name))
|
||||||
|
|
||||||
# Prepare env. var. to pass to script
|
# Prepare env. var. to pass to script
|
||||||
env_dict = _make_environment_for_app_script(app_instance_name)
|
# FIXME : workdir should be a tmp workdir
|
||||||
|
app_workdir = os.path.join(self.work_dir, "apps", app_instance_name, "settings")
|
||||||
|
env_dict = _make_environment_for_app_script(
|
||||||
|
app_instance_name, workdir=app_workdir
|
||||||
|
)
|
||||||
env_dict.update(
|
env_dict.update(
|
||||||
{
|
{
|
||||||
"YNH_BACKUP_DIR": self.work_dir,
|
"YNH_BACKUP_DIR": self.work_dir,
|
||||||
|
@ -1493,9 +1499,6 @@ class RestoreManager:
|
||||||
"YNH_APP_BACKUP_DIR": os.path.join(
|
"YNH_APP_BACKUP_DIR": os.path.join(
|
||||||
self.work_dir, "apps", app_instance_name, "backup"
|
self.work_dir, "apps", app_instance_name, "backup"
|
||||||
),
|
),
|
||||||
"YNH_APP_BASEDIR": os.path.join(
|
|
||||||
self.work_dir, "apps", app_instance_name, "settings"
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1532,11 +1535,9 @@ class RestoreManager:
|
||||||
remove_script = os.path.join(app_scripts_in_archive, "remove")
|
remove_script = os.path.join(app_scripts_in_archive, "remove")
|
||||||
|
|
||||||
# Setup environment for remove script
|
# Setup environment for remove script
|
||||||
env_dict_remove = _make_environment_for_app_script(app_instance_name)
|
env_dict_remove = _make_environment_for_app_script(
|
||||||
env_dict_remove["YNH_APP_BASEDIR"] = os.path.join(
|
app_instance_name, workdir=app_workdir
|
||||||
self.work_dir, "apps", app_instance_name, "settings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
remove_operation_logger = OperationLogger(
|
remove_operation_logger = OperationLogger(
|
||||||
"remove_on_failed_restore",
|
"remove_on_failed_restore",
|
||||||
[("app", app_instance_name)],
|
[("app", app_instance_name)],
|
||||||
|
|
|
@ -851,14 +851,9 @@ def _backup_current_cert(domain):
|
||||||
|
|
||||||
def _check_domain_is_ready_for_ACME(domain):
|
def _check_domain_is_ready_for_ACME(domain):
|
||||||
|
|
||||||
dnsrecords = (
|
from yunohost.domain import _get_parent_domain_of
|
||||||
Diagnoser.get_cached_report(
|
from yunohost.dns import _get_dns_zone_for_domain
|
||||||
"dnsrecords",
|
|
||||||
item={"domain": domain, "category": "basic"},
|
|
||||||
warn_if_no_cache=False,
|
|
||||||
)
|
|
||||||
or {}
|
|
||||||
)
|
|
||||||
httpreachable = (
|
httpreachable = (
|
||||||
Diagnoser.get_cached_report(
|
Diagnoser.get_cached_report(
|
||||||
"web", item={"domain": domain}, warn_if_no_cache=False
|
"web", item={"domain": domain}, warn_if_no_cache=False
|
||||||
|
@ -866,16 +861,47 @@ def _check_domain_is_ready_for_ACME(domain):
|
||||||
or {}
|
or {}
|
||||||
)
|
)
|
||||||
|
|
||||||
if not dnsrecords or not httpreachable:
|
parent_domain = _get_parent_domain_of(domain)
|
||||||
|
|
||||||
|
dnsrecords = (
|
||||||
|
Diagnoser.get_cached_report(
|
||||||
|
"dnsrecords",
|
||||||
|
item={"domain": parent_domain, "category": "basic"},
|
||||||
|
warn_if_no_cache=False,
|
||||||
|
)
|
||||||
|
or {}
|
||||||
|
)
|
||||||
|
|
||||||
|
base_dns_zone = _get_dns_zone_for_domain(domain)
|
||||||
|
record_name = (
|
||||||
|
domain.replace(f".{base_dns_zone}", "") if domain != base_dns_zone else "@"
|
||||||
|
)
|
||||||
|
A_record_status = dnsrecords.get("data").get(f"A:{record_name}")
|
||||||
|
AAAA_record_status = dnsrecords.get("data").get(f"AAAA:{record_name}")
|
||||||
|
|
||||||
|
# Fallback to wildcard in case no result yet for the DNS name?
|
||||||
|
if not A_record_status:
|
||||||
|
A_record_status = dnsrecords.get("data").get("A:*")
|
||||||
|
if not AAAA_record_status:
|
||||||
|
AAAA_record_status = dnsrecords.get("data").get("AAAA:*")
|
||||||
|
|
||||||
|
if (
|
||||||
|
not httpreachable
|
||||||
|
or not dnsrecords.get("data")
|
||||||
|
or (A_record_status, AAAA_record_status) == (None, None)
|
||||||
|
):
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"certmanager_domain_not_diagnosed_yet", domain=domain
|
"certmanager_domain_not_diagnosed_yet", domain=domain
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if IP from DNS matches public IP
|
# Check if IP from DNS matches public IP
|
||||||
if not dnsrecords.get("status") in [
|
# - 'MISSING' for IPv6 ain't critical for ACME
|
||||||
"SUCCESS",
|
# - IPv4 can be None assuming there's at least an IPv6, and viveversa
|
||||||
"WARNING",
|
# - (the case where both are None is checked before)
|
||||||
]: # Warning is for missing IPv6 record which ain't critical for ACME
|
if not (
|
||||||
|
A_record_status in [None, "OK"]
|
||||||
|
and AAAA_record_status in [None, "OK", "MISSING"]
|
||||||
|
):
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"certmanager_domain_dns_ip_differs_from_public_ip", domain=domain
|
"certmanager_domain_dns_ip_differs_from_public_ip", domain=domain
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,8 @@ from shutil import copy2
|
||||||
|
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
|
|
||||||
from yunohost.app import _is_installed, _patch_legacy_php_versions_in_settings
|
from yunohost.app import _is_installed
|
||||||
|
from yunohost.utils.legacy import _patch_legacy_php_versions_in_settings
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.service import _run_service_command
|
from yunohost.service import _run_service_command
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ from collections import OrderedDict
|
||||||
|
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import read_file, write_to_file, read_toml
|
from moulinette.utils.filesystem import read_file, write_to_file, read_toml, mkdir
|
||||||
|
|
||||||
from yunohost.domain import (
|
from yunohost.domain import (
|
||||||
domain_list,
|
domain_list,
|
||||||
|
@ -40,8 +40,9 @@ from yunohost.domain import (
|
||||||
domain_config_get,
|
domain_config_get,
|
||||||
_get_domain_settings,
|
_get_domain_settings,
|
||||||
_set_domain_settings,
|
_set_domain_settings,
|
||||||
|
_list_subdomains_of,
|
||||||
)
|
)
|
||||||
from yunohost.utils.dns import dig, YNH_DYNDNS_DOMAINS
|
from yunohost.utils.dns import dig, is_yunohost_dyndns_domain, is_special_use_tld
|
||||||
from yunohost.utils.error import YunohostValidationError, YunohostError
|
from yunohost.utils.error import YunohostValidationError, YunohostError
|
||||||
from yunohost.utils.network import get_public_ip
|
from yunohost.utils.network import get_public_ip
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
|
@ -61,6 +62,9 @@ def domain_dns_suggest(domain):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if is_special_use_tld(domain):
|
||||||
|
return m18n.n("domain_dns_conf_special_use_tld")
|
||||||
|
|
||||||
_assert_domain_exists(domain)
|
_assert_domain_exists(domain)
|
||||||
|
|
||||||
dns_conf = _build_dns_conf(domain)
|
dns_conf = _build_dns_conf(domain)
|
||||||
|
@ -104,18 +108,6 @@ def domain_dns_suggest(domain):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _list_subdomains_of(parent_domain):
|
|
||||||
|
|
||||||
_assert_domain_exists(parent_domain)
|
|
||||||
|
|
||||||
out = []
|
|
||||||
for domain in domain_list()["domains"]:
|
|
||||||
if domain.endswith(f".{parent_domain}"):
|
|
||||||
out.append(domain)
|
|
||||||
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
|
def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
|
||||||
"""
|
"""
|
||||||
Internal function that will returns a data structure containing the needed
|
Internal function that will returns a data structure containing the needed
|
||||||
|
@ -169,10 +161,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
|
||||||
# If this is a ynh_dyndns_domain, we're not gonna include all the subdomains in the conf
|
# If this is a ynh_dyndns_domain, we're not gonna include all the subdomains in the conf
|
||||||
# Because dynette only accept a specific list of name/type
|
# Because dynette only accept a specific list of name/type
|
||||||
# And the wildcard */A already covers the bulk of use cases
|
# And the wildcard */A already covers the bulk of use cases
|
||||||
if any(
|
if is_yunohost_dyndns_domain(base_domain):
|
||||||
base_domain.endswith("." + ynh_dyndns_domain)
|
|
||||||
for ynh_dyndns_domain in YNH_DYNDNS_DOMAINS
|
|
||||||
):
|
|
||||||
subdomains = []
|
subdomains = []
|
||||||
else:
|
else:
|
||||||
subdomains = _list_subdomains_of(base_domain)
|
subdomains = _list_subdomains_of(base_domain)
|
||||||
|
@ -297,6 +286,12 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False):
|
||||||
|
|
||||||
# Defined by custom hooks ships in apps for example ...
|
# Defined by custom hooks ships in apps for example ...
|
||||||
|
|
||||||
|
# FIXME : this ain't practical for apps that may want to add
|
||||||
|
# custom dns records for a subdomain ... there's no easy way for
|
||||||
|
# an app to compare the base domain is the parent of the subdomain ?
|
||||||
|
# (On the other hand, in sep 2021, it looks like no app is using
|
||||||
|
# this mechanism...)
|
||||||
|
|
||||||
hook_results = hook_callback("custom_dns_rules", args=[base_domain])
|
hook_results = hook_callback("custom_dns_rules", args=[base_domain])
|
||||||
for hook_name, results in hook_results.items():
|
for hook_name, results in hook_results.items():
|
||||||
#
|
#
|
||||||
|
@ -426,9 +421,14 @@ def _get_dns_zone_for_domain(domain):
|
||||||
# First, check if domain is a nohost.me / noho.st / ynh.fr
|
# First, check if domain is a nohost.me / noho.st / ynh.fr
|
||||||
# This is mainly meant to speed up things for "dyndns update"
|
# This is mainly meant to speed up things for "dyndns update"
|
||||||
# ... otherwise we end up constantly doing a bunch of dig requests
|
# ... otherwise we end up constantly doing a bunch of dig requests
|
||||||
for ynh_dyndns_domain in YNH_DYNDNS_DOMAINS:
|
if is_yunohost_dyndns_domain(domain):
|
||||||
if domain.endswith("." + ynh_dyndns_domain):
|
# Keep only foo.nohost.me even if we have subsub.sub.foo.nohost.me
|
||||||
return ynh_dyndns_domain
|
return ".".join(domain.rsplit(".", 3)[-3:])
|
||||||
|
|
||||||
|
# Same thing with .local, .test, ... domains
|
||||||
|
if is_special_use_tld(domain):
|
||||||
|
# Keep only foo.local even if we have subsub.sub.foo.local
|
||||||
|
return ".".join(domain.rsplit(".", 2)[-2:])
|
||||||
|
|
||||||
# Check cache
|
# Check cache
|
||||||
cache_folder = "/var/cache/yunohost/dns_zones"
|
cache_folder = "/var/cache/yunohost/dns_zones"
|
||||||
|
@ -471,7 +471,7 @@ def _get_dns_zone_for_domain(domain):
|
||||||
# Check if there's a NS record for that domain
|
# Check if there's a NS record for that domain
|
||||||
answer = dig(parent, rdtype="NS", full_answers=True, resolvers="force_external")
|
answer = dig(parent, rdtype="NS", full_answers=True, resolvers="force_external")
|
||||||
if answer[0] == "ok":
|
if answer[0] == "ok":
|
||||||
os.system(f"mkdir -p {cache_folder}")
|
mkdir(cache_folder, parents=True, force=True)
|
||||||
write_to_file(cache_file, parent)
|
write_to_file(cache_file, parent)
|
||||||
return parent
|
return parent
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ def _get_registrar_config_section(domain):
|
||||||
|
|
||||||
# TODO big project, integrate yunohost's dynette as a registrar-like provider
|
# TODO big project, integrate yunohost's dynette as a registrar-like provider
|
||||||
# TODO big project, integrate other dyndns providers such as netlib.re, or cf the list of dyndns providers supported by cloudron...
|
# TODO big project, integrate other dyndns providers such as netlib.re, or cf the list of dyndns providers supported by cloudron...
|
||||||
if dns_zone in YNH_DYNDNS_DOMAINS:
|
if is_yunohost_dyndns_domain(dns_zone):
|
||||||
registrar_infos["registrar"] = OrderedDict(
|
registrar_infos["registrar"] = OrderedDict(
|
||||||
{
|
{
|
||||||
"type": "alert",
|
"type": "alert",
|
||||||
|
@ -530,6 +530,15 @@ def _get_registrar_config_section(domain):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return OrderedDict(registrar_infos)
|
return OrderedDict(registrar_infos)
|
||||||
|
elif is_special_use_tld(dns_zone):
|
||||||
|
registrar_infos["registrar"] = OrderedDict(
|
||||||
|
{
|
||||||
|
"type": "alert",
|
||||||
|
"style": "info",
|
||||||
|
"ask": m18n.n("domain_dns_conf_special_use_tld"),
|
||||||
|
"value": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
registrar = _relevant_provider_for_domain(dns_zone)[0]
|
registrar = _relevant_provider_for_domain(dns_zone)[0]
|
||||||
|
@ -603,6 +612,10 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge=
|
||||||
|
|
||||||
_assert_domain_exists(domain)
|
_assert_domain_exists(domain)
|
||||||
|
|
||||||
|
if is_special_use_tld(domain):
|
||||||
|
logger.info(m18n.n("domain_dns_conf_special_use_tld"))
|
||||||
|
return {}
|
||||||
|
|
||||||
if not registrar or registrar == "None": # yes it's None as a string
|
if not registrar or registrar == "None": # yes it's None as a string
|
||||||
raise YunohostValidationError("domain_dns_push_not_applicable", domain=domain)
|
raise YunohostValidationError("domain_dns_push_not_applicable", domain=domain)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ from typing import Dict, Any
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml
|
from moulinette.utils.filesystem import write_to_file, read_yaml, write_to_yaml, rm
|
||||||
|
|
||||||
from yunohost.app import (
|
from yunohost.app import (
|
||||||
app_ssowatconf,
|
app_ssowatconf,
|
||||||
|
@ -105,6 +105,33 @@ def _assert_domain_exists(domain):
|
||||||
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
raise YunohostValidationError("domain_name_unknown", domain=domain)
|
||||||
|
|
||||||
|
|
||||||
|
def _list_subdomains_of(parent_domain):
|
||||||
|
|
||||||
|
_assert_domain_exists(parent_domain)
|
||||||
|
|
||||||
|
out = []
|
||||||
|
for domain in domain_list()["domains"]:
|
||||||
|
if domain.endswith(f".{parent_domain}"):
|
||||||
|
out.append(domain)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _get_parent_domain_of(domain):
|
||||||
|
|
||||||
|
_assert_domain_exists(domain)
|
||||||
|
|
||||||
|
if "." not in domain:
|
||||||
|
return domain
|
||||||
|
|
||||||
|
parent_domain = domain.split(".", 1)[-1]
|
||||||
|
if parent_domain not in domain_list()["domains"]:
|
||||||
|
return domain # Domain is its own parent
|
||||||
|
|
||||||
|
else:
|
||||||
|
return _get_parent_domain_of(parent_domain)
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation()
|
@is_unit_operation()
|
||||||
def domain_add(operation_logger, domain, dyndns=False):
|
def domain_add(operation_logger, domain, dyndns=False):
|
||||||
"""
|
"""
|
||||||
|
@ -301,7 +328,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
|
||||||
]
|
]
|
||||||
|
|
||||||
for stuff in stuff_to_delete:
|
for stuff in stuff_to_delete:
|
||||||
os.system("rm -rf {stuff}")
|
rm(stuff, force=True, recursive=True)
|
||||||
|
|
||||||
# Sometime we have weird issues with the regenconf where some files
|
# Sometime we have weird issues with the regenconf where some files
|
||||||
# appears as manually modified even though they weren't touched ...
|
# appears as manually modified even though they weren't touched ...
|
||||||
|
|
|
@ -33,7 +33,7 @@ import subprocess
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import write_to_file, read_file
|
from moulinette.utils.filesystem import write_to_file, read_file, rm, chown, chmod
|
||||||
from moulinette.utils.network import download_json
|
from moulinette.utils.network import download_json
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
|
@ -152,13 +152,12 @@ def dyndns_subscribe(
|
||||||
|
|
||||||
os.system(
|
os.system(
|
||||||
"cd /etc/yunohost/dyndns && "
|
"cd /etc/yunohost/dyndns && "
|
||||||
"dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s"
|
f"dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER {domain}"
|
||||||
% domain
|
|
||||||
)
|
|
||||||
os.system(
|
|
||||||
"chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
chmod("/etc/yunohost/dyndns", 0o600, recursive=True)
|
||||||
|
chown("/etc/yunohost/dyndns", "root", recursive=True)
|
||||||
|
|
||||||
private_file = glob.glob("/etc/yunohost/dyndns/*%s*.private" % domain)[0]
|
private_file = glob.glob("/etc/yunohost/dyndns/*%s*.private" % domain)[0]
|
||||||
key_file = glob.glob("/etc/yunohost/dyndns/*%s*.key" % domain)[0]
|
key_file = glob.glob("/etc/yunohost/dyndns/*%s*.key" % domain)[0]
|
||||||
with open(key_file) as f:
|
with open(key_file) as f:
|
||||||
|
@ -175,12 +174,12 @@ def dyndns_subscribe(
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
os.system("rm -f %s" % private_file)
|
rm(private_file, force=True)
|
||||||
os.system("rm -f %s" % key_file)
|
rm(key_file, force=True)
|
||||||
raise YunohostError("dyndns_registration_failed", error=str(e))
|
raise YunohostError("dyndns_registration_failed", error=str(e))
|
||||||
if r.status_code != 201:
|
if r.status_code != 201:
|
||||||
os.system("rm -f %s" % private_file)
|
rm(private_file, force=True)
|
||||||
os.system("rm -f %s" % key_file)
|
rm(key_file, force=True)
|
||||||
try:
|
try:
|
||||||
error = json.loads(r.text)["error"]
|
error = json.loads(r.text)["error"]
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -31,7 +31,6 @@ from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils import process
|
from moulinette.utils import process
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.text import prependlines
|
|
||||||
|
|
||||||
FIREWALL_FILE = "/etc/yunohost/firewall.yml"
|
FIREWALL_FILE = "/etc/yunohost/firewall.yml"
|
||||||
UPNP_CRON_JOB = "/etc/cron.d/yunohost-firewall-upnp"
|
UPNP_CRON_JOB = "/etc/cron.d/yunohost-firewall-upnp"
|
||||||
|
@ -240,7 +239,7 @@ def firewall_reload(skip_upnp=False):
|
||||||
except process.CalledProcessError as e:
|
except process.CalledProcessError as e:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"iptables seems to be not available, it outputs:\n%s",
|
"iptables seems to be not available, it outputs:\n%s",
|
||||||
prependlines(e.output.rstrip(), "> "),
|
e.output.decode().strip(),
|
||||||
)
|
)
|
||||||
logger.warning(m18n.n("iptables_unavailable"))
|
logger.warning(m18n.n("iptables_unavailable"))
|
||||||
else:
|
else:
|
||||||
|
@ -273,7 +272,7 @@ def firewall_reload(skip_upnp=False):
|
||||||
except process.CalledProcessError as e:
|
except process.CalledProcessError as e:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"ip6tables seems to be not available, it outputs:\n%s",
|
"ip6tables seems to be not available, it outputs:\n%s",
|
||||||
prependlines(e.output.rstrip(), "> "),
|
e.output.decode().strip(),
|
||||||
)
|
)
|
||||||
logger.warning(m18n.n("ip6tables_unavailable"))
|
logger.warning(m18n.n("ip6tables_unavailable"))
|
||||||
else:
|
else:
|
||||||
|
@ -526,6 +525,6 @@ def _on_rule_command_error(returncode, cmd, output):
|
||||||
'"%s" returned non-zero exit status %d:\n%s',
|
'"%s" returned non-zero exit status %d:\n%s',
|
||||||
cmd,
|
cmd,
|
||||||
returncode,
|
returncode,
|
||||||
prependlines(output.rstrip(), "> "),
|
output.decode().strip(),
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -34,7 +34,7 @@ from importlib import import_module
|
||||||
from moulinette import m18n, Moulinette
|
from moulinette import m18n, Moulinette
|
||||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from moulinette.utils import log
|
from moulinette.utils import log
|
||||||
from moulinette.utils.filesystem import read_yaml
|
from moulinette.utils.filesystem import read_yaml, cp
|
||||||
|
|
||||||
HOOK_FOLDER = "/usr/share/yunohost/hooks/"
|
HOOK_FOLDER = "/usr/share/yunohost/hooks/"
|
||||||
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
|
CUSTOM_HOOK_FOLDER = "/etc/yunohost/hooks.d/"
|
||||||
|
@ -60,8 +60,7 @@ def hook_add(app, file):
|
||||||
os.makedirs(CUSTOM_HOOK_FOLDER + action)
|
os.makedirs(CUSTOM_HOOK_FOLDER + action)
|
||||||
|
|
||||||
finalpath = CUSTOM_HOOK_FOLDER + action + "/" + priority + "-" + app
|
finalpath = CUSTOM_HOOK_FOLDER + action + "/" + priority + "-" + app
|
||||||
os.system("cp %s %s" % (file, finalpath))
|
cp(file, finalpath)
|
||||||
os.system("chown -hR admin: %s" % HOOK_FOLDER)
|
|
||||||
|
|
||||||
return {"hook": finalpath}
|
return {"hook": finalpath}
|
||||||
|
|
||||||
|
|
|
@ -407,7 +407,7 @@ def is_unit_operation(
|
||||||
if isinstance(value, IOBase):
|
if isinstance(value, IOBase):
|
||||||
try:
|
try:
|
||||||
context[field] = value.name
|
context[field] = value.name
|
||||||
except:
|
except Exception:
|
||||||
context[field] = "IOBase"
|
context[field] = "IOBase"
|
||||||
operation_logger = OperationLogger(op_key, related_to, args=context)
|
operation_logger = OperationLogger(op_key, related_to, args=context)
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,7 @@ def permission_create(
|
||||||
protected=protected,
|
protected=protected,
|
||||||
sync_perm=sync_perm,
|
sync_perm=sync_perm,
|
||||||
)
|
)
|
||||||
except:
|
except Exception:
|
||||||
permission_delete(permission, force=True)
|
permission_delete(permission, force=True)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,9 @@ def regen_conf(
|
||||||
if "glances" in names:
|
if "glances" in names:
|
||||||
names.remove("glances")
|
names.remove("glances")
|
||||||
|
|
||||||
|
if "avahi-daemon" in names:
|
||||||
|
names.remove("avahi-daemon")
|
||||||
|
|
||||||
# [Optimization] We compute and feed the domain list to the conf regen
|
# [Optimization] We compute and feed the domain list to the conf regen
|
||||||
# hooks to avoid having to call "yunohost domain list" so many times which
|
# hooks to avoid having to call "yunohost domain list" so many times which
|
||||||
# ends up in wasted time (about 3~5 seconds per call on a RPi2)
|
# ends up in wasted time (about 3~5 seconds per call on a RPi2)
|
||||||
|
@ -455,6 +458,10 @@ def _save_regenconf_infos(infos):
|
||||||
if "glances" in infos:
|
if "glances" in infos:
|
||||||
del infos["glances"]
|
del infos["glances"]
|
||||||
|
|
||||||
|
# Ugly hack to get rid of legacy avahi stuff
|
||||||
|
if "avahi-daemon" in infos:
|
||||||
|
del infos["avahi-daemon"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(REGEN_CONF_FILE, "w") as f:
|
with open(REGEN_CONF_FILE, "w") as f:
|
||||||
yaml.safe_dump(infos, f, default_flow_style=False)
|
yaml.safe_dump(infos, f, default_flow_style=False)
|
||||||
|
|
|
@ -9,7 +9,7 @@ from moulinette import m18n
|
||||||
from moulinette.utils.filesystem import read_json, write_to_json, write_to_yaml
|
from moulinette.utils.filesystem import read_json, write_to_json, write_to_yaml
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.app import (
|
from yunohost.app_catalog import (
|
||||||
_initialize_apps_catalog_system,
|
_initialize_apps_catalog_system,
|
||||||
_read_apps_catalog_list,
|
_read_apps_catalog_list,
|
||||||
_update_apps_catalog,
|
_update_apps_catalog,
|
|
@ -2,9 +2,11 @@ import glob
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import pytest
|
import pytest
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
from .conftest import get_test_apps_dir
|
from .conftest import get_test_apps_dir
|
||||||
|
|
||||||
|
from moulinette import Moulinette
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.domain import _get_maindomain
|
from yunohost.domain import _get_maindomain
|
||||||
|
@ -146,7 +148,9 @@ def test_app_config_regular_setting(config_app):
|
||||||
assert app_config_get(config_app, "main.components.boolean") == "1"
|
assert app_config_get(config_app, "main.components.boolean") == "1"
|
||||||
assert app_setting(config_app, "boolean") == "1"
|
assert app_setting(config_app, "boolean") == "1"
|
||||||
|
|
||||||
with pytest.raises(YunohostValidationError):
|
with pytest.raises(YunohostValidationError), patch.object(
|
||||||
|
os, "isatty", return_value=False
|
||||||
|
), patch.object(Moulinette, "prompt", return_value="pwet"):
|
||||||
app_config_set(config_app, "main.components.boolean", "pwet")
|
app_config_set(config_app, "main.components.boolean", "pwet")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,13 @@ def clean():
|
||||||
os.system("mkdir -p /etc/ssowat/")
|
os.system("mkdir -p /etc/ssowat/")
|
||||||
app_ssowatconf()
|
app_ssowatconf()
|
||||||
|
|
||||||
test_apps = ["break_yo_system", "legacy_app", "legacy_app__2", "full_domain_app"]
|
test_apps = [
|
||||||
|
"break_yo_system",
|
||||||
|
"legacy_app",
|
||||||
|
"legacy_app__2",
|
||||||
|
"full_domain_app",
|
||||||
|
"my_webapp",
|
||||||
|
]
|
||||||
|
|
||||||
for test_app in test_apps:
|
for test_app in test_apps:
|
||||||
|
|
||||||
|
@ -189,6 +195,32 @@ def test_legacy_app_install_main_domain():
|
||||||
assert app_is_not_installed(main_domain, "legacy_app")
|
assert app_is_not_installed(main_domain, "legacy_app")
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_from_catalog():
|
||||||
|
main_domain = _get_maindomain()
|
||||||
|
|
||||||
|
app_install(
|
||||||
|
"my_webapp",
|
||||||
|
args=f"domain={main_domain}&path=/site&with_sftp=0&password=superpassword&is_public=1&with_mysql=0",
|
||||||
|
)
|
||||||
|
app_map_ = app_map(raw=True)
|
||||||
|
assert main_domain in app_map_
|
||||||
|
assert "/site" in app_map_[main_domain]
|
||||||
|
assert "id" in app_map_[main_domain]["/site"]
|
||||||
|
assert app_map_[main_domain]["/site"]["id"] == "my_webapp"
|
||||||
|
|
||||||
|
assert app_is_installed(main_domain, "my_webapp")
|
||||||
|
assert app_is_exposed_on_http(main_domain, "/site", "Custom Web App")
|
||||||
|
|
||||||
|
# Try upgrade, should do nothing
|
||||||
|
app_upgrade("my_webapp")
|
||||||
|
# Force upgrade, should upgrade to the same version
|
||||||
|
app_upgrade("my_webapp", force=True)
|
||||||
|
|
||||||
|
app_remove("my_webapp")
|
||||||
|
|
||||||
|
assert app_is_not_installed(main_domain, "my_webapp")
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_app_install_secondary_domain(secondary_domain):
|
def test_legacy_app_install_secondary_domain(secondary_domain):
|
||||||
|
|
||||||
install_legacy_app(secondary_domain, "/legacy")
|
install_legacy_app(secondary_domain, "/legacy")
|
||||||
|
|
|
@ -4,7 +4,12 @@ import os
|
||||||
from .conftest import get_test_apps_dir
|
from .conftest import get_test_apps_dir
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.app import app_install, app_remove, _normalize_domain_path
|
from yunohost.app import (
|
||||||
|
app_install,
|
||||||
|
app_remove,
|
||||||
|
_is_app_repo_url,
|
||||||
|
_parse_app_instance_name,
|
||||||
|
)
|
||||||
from yunohost.domain import _get_maindomain, domain_url_available
|
from yunohost.domain import _get_maindomain, domain_url_available
|
||||||
from yunohost.permission import _validate_and_sanitize_permission_url
|
from yunohost.permission import _validate_and_sanitize_permission_url
|
||||||
|
|
||||||
|
@ -28,20 +33,55 @@ def teardown_function(function):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_normalize_domain_path():
|
def test_parse_app_instance_name():
|
||||||
|
|
||||||
assert _normalize_domain_path("https://yolo.swag/", "macnuggets") == (
|
assert _parse_app_instance_name("yolo") == ("yolo", 1)
|
||||||
"yolo.swag",
|
assert _parse_app_instance_name("yolo1") == ("yolo1", 1)
|
||||||
"/macnuggets",
|
assert _parse_app_instance_name("yolo__0") == ("yolo__0", 1)
|
||||||
|
assert _parse_app_instance_name("yolo__1") == ("yolo", 1)
|
||||||
|
assert _parse_app_instance_name("yolo__23") == ("yolo", 23)
|
||||||
|
assert _parse_app_instance_name("yolo__42__72") == ("yolo__42", 72)
|
||||||
|
assert _parse_app_instance_name("yolo__23qdqsd") == ("yolo__23qdqsd", 1)
|
||||||
|
assert _parse_app_instance_name("yolo__23qdqsd56") == ("yolo__23qdqsd56", 1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_repo_url_definition():
|
||||||
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foobar123_ynh")
|
||||||
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foobar123_ynh/")
|
||||||
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foobar123_ynh.git")
|
||||||
|
assert _is_app_repo_url(
|
||||||
|
"https://github.com/YunoHost-Apps/foobar123_ynh/tree/testing"
|
||||||
)
|
)
|
||||||
assert _normalize_domain_path("http://yolo.swag", "/macnuggets/") == (
|
assert _is_app_repo_url(
|
||||||
"yolo.swag",
|
"https://github.com/YunoHost-Apps/foobar123_ynh/tree/testing/"
|
||||||
"/macnuggets",
|
|
||||||
)
|
)
|
||||||
assert _normalize_domain_path("yolo.swag/", "macnuggets/") == (
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foo-bar-123_ynh")
|
||||||
"yolo.swag",
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foo_bar_123_ynh")
|
||||||
"/macnuggets",
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/FooBar123_ynh")
|
||||||
|
assert _is_app_repo_url("https://github.com/labriqueinternet/vpnclient_ynh")
|
||||||
|
assert _is_app_repo_url("https://framagit.org/YunoHost/apps/nodebb_ynh")
|
||||||
|
assert _is_app_repo_url(
|
||||||
|
"https://framagit.org/YunoHost/apps/nodebb_ynh/-/tree/testing"
|
||||||
)
|
)
|
||||||
|
assert _is_app_repo_url("https://gitlab.com/yunohost-apps/foobar_ynh")
|
||||||
|
assert _is_app_repo_url("https://code.antopie.org/miraty/qr_ynh")
|
||||||
|
assert _is_app_repo_url(
|
||||||
|
"https://gitlab.domainepublic.net/Neutrinet/neutrinet_ynh/-/tree/unstable"
|
||||||
|
)
|
||||||
|
assert _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_ynh/tree/1.23.4")
|
||||||
|
assert _is_app_repo_url("git@github.com:YunoHost-Apps/foobar_ynh.git")
|
||||||
|
|
||||||
|
assert not _is_app_repo_url("github.com/YunoHost-Apps/foobar_ynh")
|
||||||
|
assert not _is_app_repo_url("http://github.com/YunoHost-Apps/foobar_ynh")
|
||||||
|
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_wat")
|
||||||
|
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar_ynh_wat")
|
||||||
|
assert not _is_app_repo_url("https://github.com/YunoHost-Apps/foobar/tree/testing")
|
||||||
|
assert not _is_app_repo_url(
|
||||||
|
"https://github.com/YunoHost-Apps/foobar_ynh_wat/tree/testing"
|
||||||
|
)
|
||||||
|
assert not _is_app_repo_url("https://framagit.org/YunoHost/apps/")
|
||||||
|
assert not _is_app_repo_url("https://framagit.org/YunoHost/apps/pwet")
|
||||||
|
assert not _is_app_repo_url("https://framagit.org/YunoHost/apps/pwet_foo")
|
||||||
|
|
||||||
|
|
||||||
def test_urlavailable():
|
def test_urlavailable():
|
||||||
|
|
|
@ -34,8 +34,13 @@ def test_get_dns_zone_from_domain_existing():
|
||||||
assert (
|
assert (
|
||||||
_get_dns_zone_for_domain("non-existing-domain.yunohost.org") == "yunohost.org"
|
_get_dns_zone_for_domain("non-existing-domain.yunohost.org") == "yunohost.org"
|
||||||
)
|
)
|
||||||
assert _get_dns_zone_for_domain("yolo.nohost.me") == "nohost.me"
|
assert _get_dns_zone_for_domain("yolo.nohost.me") == "yolo.nohost.me"
|
||||||
assert _get_dns_zone_for_domain("foo.yolo.nohost.me") == "nohost.me"
|
assert _get_dns_zone_for_domain("foo.yolo.nohost.me") == "yolo.nohost.me"
|
||||||
|
assert _get_dns_zone_for_domain("bar.foo.yolo.nohost.me") == "yolo.nohost.me"
|
||||||
|
|
||||||
|
assert _get_dns_zone_for_domain("yolo.test") == "yolo.test"
|
||||||
|
assert _get_dns_zone_for_domain("foo.yolo.test") == "yolo.test"
|
||||||
|
|
||||||
assert _get_dns_zone_for_domain("yolo.tld") == "yolo.tld"
|
assert _get_dns_zone_for_domain("yolo.tld") == "yolo.tld"
|
||||||
assert _get_dns_zone_for_domain("foo.yolo.tld") == "yolo.tld"
|
assert _get_dns_zone_for_domain("foo.yolo.tld") == "yolo.tld"
|
||||||
|
|
||||||
|
|
|
@ -1049,7 +1049,7 @@ def test_permission_app_remove():
|
||||||
def test_permission_app_change_url():
|
def test_permission_app_change_url():
|
||||||
app_install(
|
app_install(
|
||||||
os.path.join(get_test_apps_dir(), "permissions_app_ynh"),
|
os.path.join(get_test_apps_dir(), "permissions_app_ynh"),
|
||||||
args="domain=%s&domain_2=%s&path=%s&admin=%s"
|
args="domain=%s&domain_2=%s&path=%s&is_public=1&admin=%s"
|
||||||
% (maindomain, other_domains[0], "/urlpermissionapp", "alice"),
|
% (maindomain, other_domains[0], "/urlpermissionapp", "alice"),
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
|
@ -1072,7 +1072,7 @@ def test_permission_app_change_url():
|
||||||
def test_permission_protection_management_by_helper():
|
def test_permission_protection_management_by_helper():
|
||||||
app_install(
|
app_install(
|
||||||
os.path.join(get_test_apps_dir(), "permissions_app_ynh"),
|
os.path.join(get_test_apps_dir(), "permissions_app_ynh"),
|
||||||
args="domain=%s&domain_2=%s&path=%s&admin=%s"
|
args="domain=%s&domain_2=%s&path=%s&is_public=1&admin=%s"
|
||||||
% (maindomain, other_domains[0], "/urlpermissionapp", "alice"),
|
% (maindomain, other_domains[0], "/urlpermissionapp", "alice"),
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
|
@ -1135,7 +1135,7 @@ def test_permission_legacy_app_propagation_on_ssowat():
|
||||||
|
|
||||||
app_install(
|
app_install(
|
||||||
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
|
os.path.join(get_test_apps_dir(), "legacy_app_ynh"),
|
||||||
args="domain=%s&domain_2=%s&path=%s"
|
args="domain=%s&domain_2=%s&path=%s&is_public=1"
|
||||||
% (maindomain, other_domains[0], "/legacy"),
|
% (maindomain, other_domains[0], "/legacy"),
|
||||||
force=True,
|
force=True,
|
||||||
)
|
)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,13 +34,15 @@ from typing import List
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.process import check_output, call_async_output
|
from moulinette.utils.process import check_output, call_async_output
|
||||||
from moulinette.utils.filesystem import read_yaml, write_to_yaml
|
from moulinette.utils.filesystem import read_yaml, write_to_yaml, cp, mkdir, rm
|
||||||
|
|
||||||
from yunohost.app import (
|
from yunohost.app import (
|
||||||
_update_apps_catalog,
|
|
||||||
app_info,
|
app_info,
|
||||||
app_upgrade,
|
app_upgrade,
|
||||||
|
)
|
||||||
|
from yunohost.app_catalog import (
|
||||||
_initialize_apps_catalog_system,
|
_initialize_apps_catalog_system,
|
||||||
|
_update_apps_catalog,
|
||||||
)
|
)
|
||||||
from yunohost.domain import domain_add
|
from yunohost.domain import domain_add
|
||||||
from yunohost.dyndns import _dyndns_available, _dyndns_provides
|
from yunohost.dyndns import _dyndns_available, _dyndns_provides
|
||||||
|
@ -1145,12 +1147,14 @@ class Migration(object):
|
||||||
backup_folder = "/home/yunohost.backup/premigration/" + time.strftime(
|
backup_folder = "/home/yunohost.backup/premigration/" + time.strftime(
|
||||||
"%Y%m%d-%H%M%S", time.gmtime()
|
"%Y%m%d-%H%M%S", time.gmtime()
|
||||||
)
|
)
|
||||||
os.makedirs(backup_folder, 0o750)
|
mkdir(backup_folder, 0o750, parents=True)
|
||||||
os.system("systemctl stop slapd")
|
os.system("systemctl stop slapd")
|
||||||
os.system(f"cp -r --preserve /etc/ldap {backup_folder}/ldap_config")
|
cp("/etc/ldap", f"{backup_folder}/ldap_config", recursive=True)
|
||||||
os.system(f"cp -r --preserve /var/lib/ldap {backup_folder}/ldap_db")
|
cp("/var/lib/ldap", f"{backup_folder}/ldap_db", recursive=True)
|
||||||
os.system(
|
cp(
|
||||||
f"cp -r --preserve /etc/yunohost/apps {backup_folder}/apps_settings"
|
"/etc/yunohost/apps",
|
||||||
|
f"{backup_folder}/apps_settings",
|
||||||
|
recursive=True,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise YunohostError(
|
raise YunohostError(
|
||||||
|
@ -1167,17 +1171,19 @@ class Migration(object):
|
||||||
)
|
)
|
||||||
os.system("systemctl stop slapd")
|
os.system("systemctl stop slapd")
|
||||||
# To be sure that we don't keep some part of the old config
|
# To be sure that we don't keep some part of the old config
|
||||||
os.system("rm -r /etc/ldap/slapd.d")
|
rm("/etc/ldap/slapd.d", force=True, recursive=True)
|
||||||
os.system(f"cp -r --preserve {backup_folder}/ldap_config/. /etc/ldap/")
|
cp(f"{backup_folder}/ldap_config", "/etc/ldap", recursive=True)
|
||||||
os.system(f"cp -r --preserve {backup_folder}/ldap_db/. /var/lib/ldap/")
|
cp(f"{backup_folder}/ldap_db", "/var/lib/ldap", recursive=True)
|
||||||
os.system(
|
cp(
|
||||||
f"cp -r --preserve {backup_folder}/apps_settings/. /etc/yunohost/apps/"
|
f"{backup_folder}/apps_settings",
|
||||||
|
"/etc/yunohost/apps",
|
||||||
|
recursive=True,
|
||||||
)
|
)
|
||||||
os.system("systemctl start slapd")
|
os.system("systemctl start slapd")
|
||||||
os.system(f"rm -r {backup_folder}")
|
rm(backup_folder, force=True, recursive=True)
|
||||||
logger.info(m18n.n("migration_ldap_rollback_success"))
|
logger.info(m18n.n("migration_ldap_rollback_success"))
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
os.system(f"rm -r {backup_folder}")
|
rm(backup_folder, force=True, recursive=True)
|
||||||
|
|
||||||
return func
|
return func
|
||||||
|
|
|
@ -420,7 +420,9 @@ def user_update(
|
||||||
# without a specified value, change_password will be set to the const 0.
|
# without a specified value, change_password will be set to the const 0.
|
||||||
# In this case we prompt for the new password.
|
# In this case we prompt for the new password.
|
||||||
if Moulinette.interface.type == "cli" and not change_password:
|
if Moulinette.interface.type == "cli" and not change_password:
|
||||||
change_password = Moulinette.prompt(m18n.n("ask_password"), True, True)
|
change_password = Moulinette.prompt(
|
||||||
|
m18n.n("ask_password"), is_password=True, confirm=True
|
||||||
|
)
|
||||||
# Ensure sufficiently complex password
|
# Ensure sufficiently complex password
|
||||||
assert_password_is_strong_enough("user", change_password)
|
assert_password_is_strong_enough("user", change_password)
|
||||||
|
|
||||||
|
@ -675,7 +677,7 @@ def user_import(operation_logger, csvfile, update=False, delete=False):
|
||||||
|
|
||||||
def to_list(str_list):
|
def to_list(str_list):
|
||||||
L = str_list.split(",") if str_list else []
|
L = str_list.split(",") if str_list else []
|
||||||
L = [l.strip() for l in L]
|
L = [element.strip() for element in L]
|
||||||
return L
|
return L
|
||||||
|
|
||||||
existing_users = user_list()["users"]
|
existing_users = user_list()["users"]
|
||||||
|
|
|
@ -24,13 +24,16 @@ import re
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import tempfile
|
import tempfile
|
||||||
import shutil
|
import shutil
|
||||||
|
import ast
|
||||||
|
import operator as op
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Optional, Dict, List
|
from typing import Optional, Dict, List, Union, Any, Mapping
|
||||||
|
|
||||||
from moulinette.interfaces.cli import colorize
|
from moulinette.interfaces.cli import colorize
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import (
|
from moulinette.utils.filesystem import (
|
||||||
|
read_file,
|
||||||
write_to_file,
|
write_to_file,
|
||||||
read_toml,
|
read_toml,
|
||||||
read_yaml,
|
read_yaml,
|
||||||
|
@ -45,6 +48,145 @@ from yunohost.log import OperationLogger
|
||||||
logger = getActionLogger("yunohost.config")
|
logger = getActionLogger("yunohost.config")
|
||||||
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
||||||
|
|
||||||
|
# Those js-like evaluate functions are used to eval safely visible attributes
|
||||||
|
# The goal is to evaluate in the same way than js simple-evaluate
|
||||||
|
# https://github.com/shepherdwind/simple-evaluate
|
||||||
|
def evaluate_simple_ast(node, context={}):
|
||||||
|
operators = {
|
||||||
|
ast.Not: op.not_,
|
||||||
|
ast.Mult: op.mul,
|
||||||
|
ast.Div: op.truediv, # number
|
||||||
|
ast.Mod: op.mod, # number
|
||||||
|
ast.Add: op.add, # str
|
||||||
|
ast.Sub: op.sub, # number
|
||||||
|
ast.USub: op.neg, # Negative number
|
||||||
|
ast.Gt: op.gt,
|
||||||
|
ast.Lt: op.lt,
|
||||||
|
ast.GtE: op.ge,
|
||||||
|
ast.LtE: op.le,
|
||||||
|
ast.Eq: op.eq,
|
||||||
|
ast.NotEq: op.ne,
|
||||||
|
}
|
||||||
|
context["true"] = True
|
||||||
|
context["false"] = False
|
||||||
|
context["null"] = None
|
||||||
|
|
||||||
|
# Variable
|
||||||
|
if isinstance(node, ast.Name): # Variable
|
||||||
|
return context[node.id]
|
||||||
|
|
||||||
|
# Python <=3.7 String
|
||||||
|
elif isinstance(node, ast.Str):
|
||||||
|
return node.s
|
||||||
|
|
||||||
|
# Python <=3.7 Number
|
||||||
|
elif isinstance(node, ast.Num):
|
||||||
|
return node.n
|
||||||
|
|
||||||
|
# Boolean, None and Python 3.8 for Number, Boolean, String and None
|
||||||
|
elif isinstance(node, (ast.Constant, ast.NameConstant)):
|
||||||
|
return node.value
|
||||||
|
|
||||||
|
# + - * / %
|
||||||
|
elif (
|
||||||
|
isinstance(node, ast.BinOp) and type(node.op) in operators
|
||||||
|
): # <left> <operator> <right>
|
||||||
|
left = evaluate_simple_ast(node.left, context)
|
||||||
|
right = evaluate_simple_ast(node.right, context)
|
||||||
|
if type(node.op) == ast.Add:
|
||||||
|
if isinstance(left, str) or isinstance(right, str): # support 'I am ' + 42
|
||||||
|
left = str(left)
|
||||||
|
right = str(right)
|
||||||
|
elif type(left) != type(right): # support "111" - "1" -> 110
|
||||||
|
left = float(left)
|
||||||
|
right = float(right)
|
||||||
|
|
||||||
|
return operators[type(node.op)](left, right)
|
||||||
|
|
||||||
|
# Comparison
|
||||||
|
# JS and Python don't give the same result for multi operators
|
||||||
|
# like True == 10 > 2.
|
||||||
|
elif (
|
||||||
|
isinstance(node, ast.Compare) and len(node.comparators) == 1
|
||||||
|
): # <left> <ops> <comparators>
|
||||||
|
left = evaluate_simple_ast(node.left, context)
|
||||||
|
right = evaluate_simple_ast(node.comparators[0], context)
|
||||||
|
operator = node.ops[0]
|
||||||
|
if isinstance(left, (int, float)) or isinstance(right, (int, float)):
|
||||||
|
try:
|
||||||
|
left = float(left)
|
||||||
|
right = float(right)
|
||||||
|
except ValueError:
|
||||||
|
return type(operator) == ast.NotEq
|
||||||
|
try:
|
||||||
|
return operators[type(operator)](left, right)
|
||||||
|
except TypeError: # support "e" > 1 -> False like in JS
|
||||||
|
return False
|
||||||
|
|
||||||
|
# and / or
|
||||||
|
elif isinstance(node, ast.BoolOp): # <op> <values>
|
||||||
|
for value in node.values:
|
||||||
|
value = evaluate_simple_ast(value, context)
|
||||||
|
if isinstance(node.op, ast.And) and not value:
|
||||||
|
return False
|
||||||
|
elif isinstance(node.op, ast.Or) and value:
|
||||||
|
return True
|
||||||
|
return isinstance(node.op, ast.And)
|
||||||
|
|
||||||
|
# not / USub (it's negation number -\d)
|
||||||
|
elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
|
||||||
|
return operators[type(node.op)](evaluate_simple_ast(node.operand, context))
|
||||||
|
|
||||||
|
# match function call
|
||||||
|
elif isinstance(node, ast.Call) and node.func.__dict__.get("id") == "match":
|
||||||
|
return re.match(
|
||||||
|
evaluate_simple_ast(node.args[1], context), context[node.args[0].id]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unauthorized opcode
|
||||||
|
else:
|
||||||
|
opcode = str(type(node))
|
||||||
|
raise YunohostError(
|
||||||
|
f"Unauthorize opcode '{opcode}' in visible attribute", raw_msg=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def js_to_python(expr):
|
||||||
|
in_string = None
|
||||||
|
py_expr = ""
|
||||||
|
i = 0
|
||||||
|
escaped = False
|
||||||
|
for char in expr:
|
||||||
|
if char in r"\"'":
|
||||||
|
# Start a string
|
||||||
|
if not in_string:
|
||||||
|
in_string = char
|
||||||
|
|
||||||
|
# Finish a string
|
||||||
|
elif in_string == char and not escaped:
|
||||||
|
in_string = None
|
||||||
|
|
||||||
|
# If we are not in a string, replace operators
|
||||||
|
elif not in_string:
|
||||||
|
if char == "!" and expr[i + 1] != "=":
|
||||||
|
char = "not "
|
||||||
|
elif char in "|&" and py_expr[-1:] == char:
|
||||||
|
py_expr = py_expr[:-1]
|
||||||
|
char = " and " if char == "&" else " or "
|
||||||
|
|
||||||
|
# Determine if next loop will be in escaped mode
|
||||||
|
escaped = char == "\\" and not escaped
|
||||||
|
py_expr += char
|
||||||
|
i += 1
|
||||||
|
return py_expr
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate_simple_js_expression(expr, context={}):
|
||||||
|
if not expr.strip():
|
||||||
|
return False
|
||||||
|
node = ast.parse(js_to_python(expr), mode="eval").body
|
||||||
|
return evaluate_simple_ast(node, context)
|
||||||
|
|
||||||
|
|
||||||
class ConfigPanel:
|
class ConfigPanel:
|
||||||
def __init__(self, config_path, save_path=None):
|
def __init__(self, config_path, save_path=None):
|
||||||
|
@ -99,6 +241,11 @@ class ConfigPanel:
|
||||||
result[key]["value"] = question_class.humanize(
|
result[key]["value"] = question_class.humanize(
|
||||||
option["current_value"], option
|
option["current_value"], option
|
||||||
)
|
)
|
||||||
|
# FIXME: semantics, technically here this is not about a prompt...
|
||||||
|
if question_class.hide_user_input_in_prompt:
|
||||||
|
result[key][
|
||||||
|
"value"
|
||||||
|
] = "**************" # Prevent displaying password in `config get`
|
||||||
|
|
||||||
if mode == "full":
|
if mode == "full":
|
||||||
return self.config
|
return self.config
|
||||||
|
@ -164,6 +311,9 @@ class ConfigPanel:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
# Delete files uploaded from API
|
# Delete files uploaded from API
|
||||||
|
# FIXME : this is currently done in the context of config panels,
|
||||||
|
# but could also happen in the context of app install ... (or anywhere else
|
||||||
|
# where we may parse args etc...)
|
||||||
FileQuestion.clean_upload_dirs()
|
FileQuestion.clean_upload_dirs()
|
||||||
|
|
||||||
self._reload_services()
|
self._reload_services()
|
||||||
|
@ -198,20 +348,20 @@ class ConfigPanel:
|
||||||
|
|
||||||
# Transform toml format into internal format
|
# Transform toml format into internal format
|
||||||
format_description = {
|
format_description = {
|
||||||
"toml": {
|
"root": {
|
||||||
"properties": ["version", "i18n"],
|
"properties": ["version", "i18n"],
|
||||||
"default": {"version": 1.0},
|
"defaults": {"version": 1.0},
|
||||||
},
|
},
|
||||||
"panels": {
|
"panels": {
|
||||||
"properties": ["name", "services", "actions", "help"],
|
"properties": ["name", "services", "actions", "help"],
|
||||||
"default": {
|
"defaults": {
|
||||||
"services": [],
|
"services": [],
|
||||||
"actions": {"apply": {"en": "Apply"}},
|
"actions": {"apply": {"en": "Apply"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sections": {
|
"sections": {
|
||||||
"properties": ["name", "services", "optional", "help", "visible"],
|
"properties": ["name", "services", "optional", "help", "visible"],
|
||||||
"default": {
|
"defaults": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"services": [],
|
"services": [],
|
||||||
"optional": True,
|
"optional": True,
|
||||||
|
@ -241,11 +391,11 @@ class ConfigPanel:
|
||||||
"accept",
|
"accept",
|
||||||
"redact",
|
"redact",
|
||||||
],
|
],
|
||||||
"default": {},
|
"defaults": {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def convert(toml_node, node_type):
|
def _build_internal_config_panel(raw_infos, level):
|
||||||
"""Convert TOML in internal format ('full' mode used by webadmin)
|
"""Convert TOML in internal format ('full' mode used by webadmin)
|
||||||
Here are some properties of 1.0 config panel in toml:
|
Here are some properties of 1.0 config panel in toml:
|
||||||
- node properties and node children are mixed,
|
- node properties and node children are mixed,
|
||||||
|
@ -253,48 +403,47 @@ class ConfigPanel:
|
||||||
- some properties have default values
|
- some properties have default values
|
||||||
This function detects all children nodes and put them in a list
|
This function detects all children nodes and put them in a list
|
||||||
"""
|
"""
|
||||||
# Prefill the node default keys if needed
|
|
||||||
default = format_description[node_type]["default"]
|
|
||||||
node = {key: toml_node.get(key, value) for key, value in default.items()}
|
|
||||||
|
|
||||||
properties = format_description[node_type]["properties"]
|
defaults = format_description[level]["defaults"]
|
||||||
|
properties = format_description[level]["properties"]
|
||||||
|
|
||||||
# Define the filter_key part to use and the children type
|
# Start building the ouput (merging the raw infos + defaults)
|
||||||
i = list(format_description).index(node_type)
|
out = {key: raw_infos.get(key, value) for key, value in defaults.items()}
|
||||||
subnode_type = (
|
|
||||||
list(format_description)[i + 1] if node_type != "options" else None
|
# Now fill the sublevels (+ apply filter_key)
|
||||||
)
|
i = list(format_description).index(level)
|
||||||
|
sublevel = list(format_description)[i + 1] if level != "options" else None
|
||||||
search_key = filter_key[i] if len(filter_key) > i else False
|
search_key = filter_key[i] if len(filter_key) > i else False
|
||||||
|
|
||||||
for key, value in toml_node.items():
|
for key, value in raw_infos.items():
|
||||||
# Key/value are a child node
|
# Key/value are a child node
|
||||||
if (
|
if (
|
||||||
isinstance(value, OrderedDict)
|
isinstance(value, OrderedDict)
|
||||||
and key not in properties
|
and key not in properties
|
||||||
and subnode_type
|
and sublevel
|
||||||
):
|
):
|
||||||
# We exclude all nodes not referenced by the filter_key
|
# We exclude all nodes not referenced by the filter_key
|
||||||
if search_key and key != search_key:
|
if search_key and key != search_key:
|
||||||
continue
|
continue
|
||||||
subnode = convert(value, subnode_type)
|
subnode = _build_internal_config_panel(value, sublevel)
|
||||||
subnode["id"] = key
|
subnode["id"] = key
|
||||||
if node_type == "toml":
|
if level == "root":
|
||||||
subnode.setdefault("name", {"en": key.capitalize()})
|
subnode.setdefault("name", {"en": key.capitalize()})
|
||||||
elif node_type == "sections":
|
elif level == "sections":
|
||||||
subnode["name"] = key # legacy
|
subnode["name"] = key # legacy
|
||||||
subnode.setdefault("optional", toml_node.get("optional", True))
|
subnode.setdefault("optional", raw_infos.get("optional", True))
|
||||||
node.setdefault(subnode_type, []).append(subnode)
|
out.setdefault(sublevel, []).append(subnode)
|
||||||
# Key/value are a property
|
# Key/value are a property
|
||||||
else:
|
else:
|
||||||
if key not in properties:
|
if key not in properties:
|
||||||
logger.warning(f"Unknown key '{key}' found in config toml")
|
logger.warning(f"Unknown key '{key}' found in config panel")
|
||||||
# Todo search all i18n keys
|
# Todo search all i18n keys
|
||||||
node[key] = (
|
out[key] = (
|
||||||
value if key not in ["ask", "help", "name"] else {"en": value}
|
value if key not in ["ask", "help", "name"] else {"en": value}
|
||||||
)
|
)
|
||||||
return node
|
return out
|
||||||
|
|
||||||
self.config = convert(toml_config_panel, "toml")
|
self.config = _build_internal_config_panel(toml_config_panel, "root")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.config["panels"][0]["sections"][0]["options"][0]
|
self.config["panels"][0]["sections"][0]["options"][0]
|
||||||
|
@ -376,14 +525,15 @@ class ConfigPanel:
|
||||||
display_header(f"\n# {name}")
|
display_header(f"\n# {name}")
|
||||||
|
|
||||||
# Check and ask unanswered questions
|
# Check and ask unanswered questions
|
||||||
|
questions = ask_questions_and_parse_answers(section["options"], self.args)
|
||||||
self.new_values.update(
|
self.new_values.update(
|
||||||
parse_args_in_yunohost_format(self.args, section["options"])
|
{
|
||||||
)
|
question.name: question.value
|
||||||
self.new_values = {
|
for question in questions
|
||||||
key: value[0]
|
if question.value is not None
|
||||||
for key, value in self.new_values.items()
|
|
||||||
if not value[0] is None
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
self.errors = None
|
self.errors = None
|
||||||
|
|
||||||
def _get_default_values(self):
|
def _get_default_values(self):
|
||||||
|
@ -457,18 +607,22 @@ class Question(object):
|
||||||
hide_user_input_in_prompt = False
|
hide_user_input_in_prompt = False
|
||||||
pattern: Optional[Dict] = None
|
pattern: Optional[Dict] = None
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question: Dict[str, Any], context: Mapping[str, Any] = {}):
|
||||||
self.name = question["name"]
|
self.name = question["name"]
|
||||||
self.type = question.get("type", "string")
|
self.type = question.get("type", "string")
|
||||||
self.default = question.get("default", None)
|
self.default = question.get("default", None)
|
||||||
self.current_value = question.get("current_value")
|
|
||||||
self.optional = question.get("optional", False)
|
self.optional = question.get("optional", False)
|
||||||
|
self.visible = question.get("visible", None)
|
||||||
|
self.context = context
|
||||||
self.choices = question.get("choices", [])
|
self.choices = question.get("choices", [])
|
||||||
self.pattern = question.get("pattern", self.pattern)
|
self.pattern = question.get("pattern", self.pattern)
|
||||||
self.ask = question.get("ask", {"en": self.name})
|
self.ask = question.get("ask", {"en": self.name})
|
||||||
self.help = question.get("help")
|
self.help = question.get("help")
|
||||||
self.value = user_answers.get(self.name)
|
|
||||||
self.redact = question.get("redact", False)
|
self.redact = question.get("redact", False)
|
||||||
|
# .current_value is the currently stored value
|
||||||
|
self.current_value = question.get("current_value")
|
||||||
|
# .value is the "proposed" value which we got from the user
|
||||||
|
self.value = question.get("value")
|
||||||
|
|
||||||
# Empty value is parsed as empty string
|
# Empty value is parsed as empty string
|
||||||
if self.default == "":
|
if self.default == "":
|
||||||
|
@ -480,6 +634,8 @@ class Question(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize(value, option={}):
|
def normalize(value, option={}):
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.strip()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _prompt(self, text):
|
def _prompt(self, text):
|
||||||
|
@ -491,12 +647,25 @@ class Question(object):
|
||||||
self.value = Moulinette.prompt(
|
self.value = Moulinette.prompt(
|
||||||
message=text,
|
message=text,
|
||||||
is_password=self.hide_user_input_in_prompt,
|
is_password=self.hide_user_input_in_prompt,
|
||||||
confirm=False, # We doesn't want to confirm this kind of password like in webadmin
|
confirm=False,
|
||||||
prefill=prefill,
|
prefill=prefill,
|
||||||
is_multiline=(self.type == "text"),
|
is_multiline=(self.type == "text"),
|
||||||
|
autocomplete=self.choices,
|
||||||
|
help=_value_for_locale(self.help),
|
||||||
)
|
)
|
||||||
|
|
||||||
def ask_if_needed(self):
|
def ask_if_needed(self):
|
||||||
|
|
||||||
|
if self.visible and not evaluate_simple_js_expression(
|
||||||
|
self.visible, context=self.context
|
||||||
|
):
|
||||||
|
# FIXME There could be several use case if the question is not displayed:
|
||||||
|
# - we doesn't want to give a specific value
|
||||||
|
# - we want to keep the previous value
|
||||||
|
# - we want the default value
|
||||||
|
self.value = None
|
||||||
|
return self.value
|
||||||
|
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
# Display question if no value filled or if it's a readonly message
|
# Display question if no value filled or if it's a readonly message
|
||||||
if Moulinette.interface.type == "cli" and os.isatty(1):
|
if Moulinette.interface.type == "cli" and os.isatty(1):
|
||||||
|
@ -513,12 +682,9 @@ class Question(object):
|
||||||
):
|
):
|
||||||
self.value = class_default if self.default is None else self.default
|
self.value = class_default if self.default is None else self.default
|
||||||
|
|
||||||
# Normalization
|
|
||||||
# This is done to enforce a certain formating like for boolean
|
|
||||||
self.value = self.normalize(self.value, self)
|
|
||||||
|
|
||||||
# Prevalidation
|
|
||||||
try:
|
try:
|
||||||
|
# Normalize and validate
|
||||||
|
self.value = self.normalize(self.value, self)
|
||||||
self._prevalidate()
|
self._prevalidate()
|
||||||
except YunohostValidationError as e:
|
except YunohostValidationError as e:
|
||||||
# If in interactive cli, re-ask the current question
|
# If in interactive cli, re-ask the current question
|
||||||
|
@ -531,9 +697,10 @@ class Question(object):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
self.value = self._post_parse_value()
|
self.value = self._post_parse_value()
|
||||||
|
|
||||||
return (self.value, self.argument_type)
|
return self.value
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
if self.value in [None, ""] and not self.optional:
|
if self.value in [None, ""] and not self.optional:
|
||||||
|
@ -542,7 +709,12 @@ class Question(object):
|
||||||
# we have an answer, do some post checks
|
# we have an answer, do some post checks
|
||||||
if self.value not in [None, ""]:
|
if self.value not in [None, ""]:
|
||||||
if self.choices and self.value not in self.choices:
|
if self.choices and self.value not in self.choices:
|
||||||
self._raise_invalid_answer()
|
raise YunohostValidationError(
|
||||||
|
"app_argument_choice_invalid",
|
||||||
|
name=self.name,
|
||||||
|
value=self.value,
|
||||||
|
choices=", ".join(self.choices),
|
||||||
|
)
|
||||||
if self.pattern and not re.match(self.pattern["regexp"], str(self.value)):
|
if self.pattern and not re.match(self.pattern["regexp"], str(self.value)):
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
self.pattern["error"],
|
self.pattern["error"],
|
||||||
|
@ -550,25 +722,31 @@ class Question(object):
|
||||||
value=self.value,
|
value=self.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _raise_invalid_answer(self):
|
def _format_text_for_user_input_in_cli(self):
|
||||||
raise YunohostValidationError(
|
|
||||||
"app_argument_choice_invalid",
|
|
||||||
name=self.name,
|
|
||||||
value=self.value,
|
|
||||||
choices=", ".join(self.choices),
|
|
||||||
)
|
|
||||||
|
|
||||||
def _format_text_for_user_input_in_cli(self, column=False):
|
|
||||||
text_for_user_input_in_cli = _value_for_locale(self.ask)
|
text_for_user_input_in_cli = _value_for_locale(self.ask)
|
||||||
|
|
||||||
if self.choices:
|
if self.choices:
|
||||||
text_for_user_input_in_cli += " [{0}]".format(" | ".join(self.choices))
|
|
||||||
|
|
||||||
if self.help or column:
|
# Prevent displaying a shitload of choices
|
||||||
text_for_user_input_in_cli += ":\033[m"
|
# (e.g. 100+ available users when choosing an app admin...)
|
||||||
if self.help:
|
choices = (
|
||||||
text_for_user_input_in_cli += "\n - "
|
list(self.choices.keys())
|
||||||
text_for_user_input_in_cli += _value_for_locale(self.help)
|
if isinstance(self.choices, dict)
|
||||||
|
else self.choices
|
||||||
|
)
|
||||||
|
choices_to_display = choices[:20]
|
||||||
|
remaining_choices = len(choices[20:])
|
||||||
|
|
||||||
|
if remaining_choices > 0:
|
||||||
|
choices_to_display += [
|
||||||
|
m18n.n("other_available_options", n=remaining_choices)
|
||||||
|
]
|
||||||
|
|
||||||
|
choices_to_display = " | ".join(choices_to_display)
|
||||||
|
|
||||||
|
text_for_user_input_in_cli += f" [{choices_to_display}]"
|
||||||
|
|
||||||
return text_for_user_input_in_cli
|
return text_for_user_input_in_cli
|
||||||
|
|
||||||
def _post_parse_value(self):
|
def _post_parse_value(self):
|
||||||
|
@ -659,6 +837,8 @@ class TagsQuestion(Question):
|
||||||
def normalize(value, option={}):
|
def normalize(value, option={}):
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
return ",".join(value)
|
return ",".join(value)
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.strip()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
|
@ -684,20 +864,14 @@ class PasswordQuestion(Question):
|
||||||
default_value = ""
|
default_value = ""
|
||||||
forbidden_chars = "{}"
|
forbidden_chars = "{}"
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
self.redact = True
|
self.redact = True
|
||||||
if self.default is not None:
|
if self.default is not None:
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_password_no_default", name=self.name
|
"app_argument_password_no_default", name=self.name
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def humanize(value, option={}):
|
|
||||||
if value:
|
|
||||||
return "********" # Avoid to display the password on screen
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
super()._prevalidate()
|
super()._prevalidate()
|
||||||
|
|
||||||
|
@ -712,34 +886,31 @@ class PasswordQuestion(Question):
|
||||||
|
|
||||||
assert_password_is_strong_enough("user", self.value)
|
assert_password_is_strong_enough("user", self.value)
|
||||||
|
|
||||||
def _format_text_for_user_input_in_cli(self):
|
|
||||||
need_column = self.current_value or self.optional
|
|
||||||
text_for_user_input_in_cli = super()._format_text_for_user_input_in_cli(
|
|
||||||
need_column
|
|
||||||
)
|
|
||||||
if self.current_value:
|
|
||||||
text_for_user_input_in_cli += "\n - " + m18n.n(
|
|
||||||
"app_argument_password_help_keep"
|
|
||||||
)
|
|
||||||
if self.optional:
|
|
||||||
text_for_user_input_in_cli += "\n - " + m18n.n(
|
|
||||||
"app_argument_password_help_optional"
|
|
||||||
)
|
|
||||||
|
|
||||||
return text_for_user_input_in_cli
|
|
||||||
|
|
||||||
def _prompt(self, text):
|
|
||||||
super()._prompt(text)
|
|
||||||
if self.current_value and self.value == "":
|
|
||||||
self.value = self.current_value
|
|
||||||
elif self.value == " ":
|
|
||||||
self.value = ""
|
|
||||||
|
|
||||||
|
|
||||||
class PathQuestion(Question):
|
class PathQuestion(Question):
|
||||||
argument_type = "path"
|
argument_type = "path"
|
||||||
default_value = ""
|
default_value = ""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def normalize(value, option={}):
|
||||||
|
|
||||||
|
option = option.__dict__ if isinstance(option, Question) else option
|
||||||
|
|
||||||
|
if not value.strip():
|
||||||
|
if option.get("optional"):
|
||||||
|
return ""
|
||||||
|
# Hmpf here we could just have a "else" case
|
||||||
|
# but we also want PathQuestion.normalize("") to return "/"
|
||||||
|
# (i.e. if no option is provided, hence .get("optional") is None
|
||||||
|
elif option.get("optional") is False:
|
||||||
|
raise YunohostValidationError(
|
||||||
|
"app_argument_invalid",
|
||||||
|
name=option.get("name"),
|
||||||
|
error="Question is mandatory",
|
||||||
|
)
|
||||||
|
|
||||||
|
return "/" + value.strip().strip(" /")
|
||||||
|
|
||||||
|
|
||||||
class BooleanQuestion(Question):
|
class BooleanQuestion(Question):
|
||||||
argument_type = "boolean"
|
argument_type = "boolean"
|
||||||
|
@ -750,50 +921,70 @@ class BooleanQuestion(Question):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def humanize(value, option={}):
|
def humanize(value, option={}):
|
||||||
|
|
||||||
|
option = option.__dict__ if isinstance(option, Question) else option
|
||||||
|
|
||||||
yes = option.get("yes", 1)
|
yes = option.get("yes", 1)
|
||||||
no = option.get("no", 0)
|
no = option.get("no", 0)
|
||||||
value = str(value).lower()
|
|
||||||
if value == str(yes).lower():
|
|
||||||
return "yes"
|
|
||||||
if value == str(no).lower():
|
|
||||||
return "no"
|
|
||||||
if value in BooleanQuestion.yes_answers:
|
|
||||||
return "yes"
|
|
||||||
if value in BooleanQuestion.no_answers:
|
|
||||||
return "no"
|
|
||||||
|
|
||||||
if value in ["none", ""]:
|
value = BooleanQuestion.normalize(value, option)
|
||||||
|
|
||||||
|
if value == yes:
|
||||||
|
return "yes"
|
||||||
|
if value == no:
|
||||||
|
return "no"
|
||||||
|
if value is None:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_choice_invalid",
|
"app_argument_choice_invalid",
|
||||||
name=option.get("name", ""),
|
name=option.get("name"),
|
||||||
value=value,
|
value=value,
|
||||||
choices="yes, no, y, n, 1, 0",
|
choices="yes/no",
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize(value, option={}):
|
def normalize(value, option={}):
|
||||||
yes = option.get("yes", 1)
|
|
||||||
no = option.get("no", 0)
|
|
||||||
|
|
||||||
if str(value).lower() in BooleanQuestion.yes_answers:
|
option = option.__dict__ if isinstance(option, Question) else option
|
||||||
return yes
|
|
||||||
|
|
||||||
if str(value).lower() in BooleanQuestion.no_answers:
|
if isinstance(value, str):
|
||||||
return no
|
value = value.strip()
|
||||||
|
|
||||||
if value in [None, ""]:
|
technical_yes = option.get("yes", 1)
|
||||||
|
technical_no = option.get("no", 0)
|
||||||
|
|
||||||
|
no_answers = BooleanQuestion.no_answers
|
||||||
|
yes_answers = BooleanQuestion.yes_answers
|
||||||
|
|
||||||
|
assert (
|
||||||
|
str(technical_yes).lower() not in no_answers
|
||||||
|
), f"'yes' value can't be in {no_answers}"
|
||||||
|
assert (
|
||||||
|
str(technical_no).lower() not in yes_answers
|
||||||
|
), f"'no' value can't be in {yes_answers}"
|
||||||
|
|
||||||
|
no_answers += [str(technical_no).lower()]
|
||||||
|
yes_answers += [str(technical_yes).lower()]
|
||||||
|
|
||||||
|
strvalue = str(value).lower()
|
||||||
|
|
||||||
|
if strvalue in yes_answers:
|
||||||
|
return technical_yes
|
||||||
|
if strvalue in no_answers:
|
||||||
|
return technical_no
|
||||||
|
|
||||||
|
if strvalue in ["none", ""]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_choice_invalid",
|
"app_argument_choice_invalid",
|
||||||
name=option.get("name", ""),
|
name=option.get("name"),
|
||||||
value=value,
|
value=strvalue,
|
||||||
choices="yes, no, y, n, 1, 0",
|
choices="yes/no",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
self.yes = question.get("yes", 1)
|
self.yes = question.get("yes", 1)
|
||||||
self.no = question.get("no", 0)
|
self.no = question.get("no", 0)
|
||||||
if self.default is None:
|
if self.default is None:
|
||||||
|
@ -807,42 +998,44 @@ class BooleanQuestion(Question):
|
||||||
return text_for_user_input_in_cli
|
return text_for_user_input_in_cli
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
try:
|
return getattr(self, key, default)
|
||||||
return getattr(self, key)
|
|
||||||
except AttributeError:
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
class DomainQuestion(Question):
|
class DomainQuestion(Question):
|
||||||
argument_type = "domain"
|
argument_type = "domain"
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
from yunohost.domain import domain_list, _get_maindomain
|
from yunohost.domain import domain_list, _get_maindomain
|
||||||
|
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
|
|
||||||
if self.default is None:
|
if self.default is None:
|
||||||
self.default = _get_maindomain()
|
self.default = _get_maindomain()
|
||||||
|
|
||||||
self.choices = domain_list()["domains"]
|
self.choices = domain_list()["domains"]
|
||||||
|
|
||||||
def _raise_invalid_answer(self):
|
@staticmethod
|
||||||
raise YunohostValidationError(
|
def normalize(value, option={}):
|
||||||
"app_argument_invalid",
|
if value.startswith("https://"):
|
||||||
name=self.name,
|
value = value[len("https://") :]
|
||||||
error=m18n.n("domain_name_unknown", domain=self.value),
|
elif value.startswith("http://"):
|
||||||
)
|
value = value[len("http://") :]
|
||||||
|
|
||||||
|
# Remove trailing slashes
|
||||||
|
value = value.rstrip("/").lower()
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class UserQuestion(Question):
|
class UserQuestion(Question):
|
||||||
argument_type = "user"
|
argument_type = "user"
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
from yunohost.user import user_list, user_info
|
from yunohost.user import user_list, user_info
|
||||||
from yunohost.domain import _get_maindomain
|
from yunohost.domain import _get_maindomain
|
||||||
|
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
self.choices = user_list()["users"]
|
self.choices = list(user_list()["users"].keys())
|
||||||
|
|
||||||
if not self.choices:
|
if not self.choices:
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
|
@ -853,42 +1046,42 @@ class UserQuestion(Question):
|
||||||
|
|
||||||
if self.default is None:
|
if self.default is None:
|
||||||
root_mail = "root@%s" % _get_maindomain()
|
root_mail = "root@%s" % _get_maindomain()
|
||||||
for user in self.choices.keys():
|
for user in self.choices:
|
||||||
if root_mail in user_info(user).get("mail-aliases", []):
|
if root_mail in user_info(user).get("mail-aliases", []):
|
||||||
self.default = user
|
self.default = user
|
||||||
break
|
break
|
||||||
|
|
||||||
def _raise_invalid_answer(self):
|
|
||||||
raise YunohostValidationError(
|
|
||||||
"app_argument_invalid",
|
|
||||||
name=self.name,
|
|
||||||
error=m18n.n("user_unknown", user=self.value),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class NumberQuestion(Question):
|
class NumberQuestion(Question):
|
||||||
argument_type = "number"
|
argument_type = "number"
|
||||||
default_value = None
|
default_value = None
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
self.min = question.get("min", None)
|
self.min = question.get("min", None)
|
||||||
self.max = question.get("max", None)
|
self.max = question.get("max", None)
|
||||||
self.step = question.get("step", None)
|
self.step = question.get("step", None)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize(value, option={}):
|
def normalize(value, option={}):
|
||||||
|
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.strip()
|
||||||
|
|
||||||
if isinstance(value, str) and value.isdigit():
|
if isinstance(value, str) and value.isdigit():
|
||||||
return int(value)
|
return int(value)
|
||||||
|
|
||||||
if value in [None, ""]:
|
if value in [None, ""]:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
option = option.__dict__ if isinstance(option, Question) else option
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_invalid", name=option.name, error=m18n.n("invalid_number")
|
"app_argument_invalid",
|
||||||
|
name=option.get("name"),
|
||||||
|
error=m18n.n("invalid_number"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
|
@ -915,8 +1108,8 @@ class DisplayTextQuestion(Question):
|
||||||
argument_type = "display_text"
|
argument_type = "display_text"
|
||||||
readonly = True
|
readonly = True
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
|
|
||||||
self.optional = True
|
self.optional = True
|
||||||
self.style = question.get(
|
self.style = question.get(
|
||||||
|
@ -946,90 +1139,53 @@ class FileQuestion(Question):
|
||||||
@classmethod
|
@classmethod
|
||||||
def clean_upload_dirs(cls):
|
def clean_upload_dirs(cls):
|
||||||
# Delete files uploaded from API
|
# Delete files uploaded from API
|
||||||
if Moulinette.interface.type == "api":
|
|
||||||
for upload_dir in cls.upload_dirs:
|
for upload_dir in cls.upload_dirs:
|
||||||
if os.path.exists(upload_dir):
|
if os.path.exists(upload_dir):
|
||||||
shutil.rmtree(upload_dir)
|
shutil.rmtree(upload_dir)
|
||||||
|
|
||||||
def __init__(self, question, user_answers):
|
def __init__(self, question, context: Mapping[str, Any] = {}):
|
||||||
super().__init__(question, user_answers)
|
super().__init__(question, context)
|
||||||
if question.get("accept"):
|
self.accept = question.get("accept", "")
|
||||||
self.accept = question.get("accept")
|
|
||||||
else:
|
|
||||||
self.accept = ""
|
|
||||||
if Moulinette.interface.type == "api":
|
|
||||||
if user_answers.get(f"{self.name}[name]"):
|
|
||||||
self.value = {
|
|
||||||
"content": self.value,
|
|
||||||
"filename": user_answers.get(f"{self.name}[name]", self.name),
|
|
||||||
}
|
|
||||||
|
|
||||||
def _prevalidate(self):
|
def _prevalidate(self):
|
||||||
if self.value is None:
|
if self.value is None:
|
||||||
self.value = self.current_value
|
self.value = self.current_value
|
||||||
|
|
||||||
super()._prevalidate()
|
super()._prevalidate()
|
||||||
if (
|
|
||||||
isinstance(self.value, str)
|
|
||||||
and self.value
|
|
||||||
and not os.path.exists(self.value)
|
|
||||||
):
|
|
||||||
raise YunohostValidationError(
|
|
||||||
"app_argument_invalid",
|
|
||||||
name=self.name,
|
|
||||||
error=m18n.n("file_does_not_exist", path=self.value),
|
|
||||||
)
|
|
||||||
if self.value in [None, ""] or not self.accept:
|
|
||||||
return
|
|
||||||
|
|
||||||
filename = self.value if isinstance(self.value, str) else self.value["filename"]
|
if Moulinette.interface.type != "api":
|
||||||
if "." not in filename or "." + filename.split(".")[
|
if not self.value or not os.path.exists(str(self.value)):
|
||||||
-1
|
|
||||||
] not in self.accept.replace(" ", "").split(","):
|
|
||||||
raise YunohostValidationError(
|
raise YunohostValidationError(
|
||||||
"app_argument_invalid",
|
"app_argument_invalid",
|
||||||
name=self.name,
|
name=self.name,
|
||||||
error=m18n.n(
|
error=m18n.n("file_does_not_exist", path=str(self.value)),
|
||||||
"file_extension_not_accepted", file=filename, accept=self.accept
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _post_parse_value(self):
|
def _post_parse_value(self):
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
|
|
||||||
# Upload files from API
|
|
||||||
# A file arg contains a string with "FILENAME:BASE64_CONTENT"
|
|
||||||
if not self.value:
|
if not self.value:
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
if Moulinette.interface.type == "api" and isinstance(self.value, dict):
|
upload_dir = tempfile.mkdtemp(prefix="ynh_filequestion_")
|
||||||
|
_, file_path = tempfile.mkstemp(dir=upload_dir)
|
||||||
|
|
||||||
upload_dir = tempfile.mkdtemp(prefix="tmp_configpanel_")
|
|
||||||
FileQuestion.upload_dirs += [upload_dir]
|
FileQuestion.upload_dirs += [upload_dir]
|
||||||
filename = self.value["filename"]
|
|
||||||
logger.debug(
|
|
||||||
f"Save uploaded file {self.value['filename']} from API into {upload_dir}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Filename is given by user of the API. For security reason, we have replaced
|
logger.debug(f"Saving file {self.name} for file question into {file_path}")
|
||||||
# os.path.join to avoid the user to be able to rewrite a file in filesystem
|
|
||||||
# i.e. os.path.join("/foo", "/etc/passwd") == "/etc/passwd"
|
|
||||||
file_path = os.path.normpath(upload_dir + "/" + filename)
|
|
||||||
if not file_path.startswith(upload_dir + "/"):
|
|
||||||
raise YunohostError(
|
|
||||||
f"Filename '{filename}' received from the API got a relative parent path, which is forbidden",
|
|
||||||
raw_msg=True,
|
|
||||||
)
|
|
||||||
i = 2
|
|
||||||
while os.path.exists(file_path):
|
|
||||||
file_path = os.path.normpath(upload_dir + "/" + filename + (".%d" % i))
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
content = self.value["content"]
|
def is_file_path(s):
|
||||||
|
return isinstance(s, str) and s.startswith("/") and os.path.exists(s)
|
||||||
|
|
||||||
write_to_file(file_path, b64decode(content), file_mode="wb")
|
if Moulinette.interface.type != "api" or is_file_path(self.value):
|
||||||
|
content = read_file(str(self.value), file_mode="rb")
|
||||||
|
else:
|
||||||
|
content = b64decode(self.value)
|
||||||
|
|
||||||
|
write_to_file(file_path, content, file_mode="wb")
|
||||||
|
|
||||||
self.value = file_path
|
self.value = file_path
|
||||||
|
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
@ -1057,25 +1213,41 @@ ARGUMENTS_TYPE_PARSERS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse_args_in_yunohost_format(user_answers, argument_questions):
|
def ask_questions_and_parse_answers(
|
||||||
|
raw_questions: Dict, prefilled_answers: Union[str, Mapping[str, Any]] = {}
|
||||||
|
) -> List[Question]:
|
||||||
"""Parse arguments store in either manifest.json or actions.json or from a
|
"""Parse arguments store in either manifest.json or actions.json or from a
|
||||||
config panel against the user answers when they are present.
|
config panel against the user answers when they are present.
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
user_answers -- a dictionnary of arguments from the user (generally
|
raw_questions -- the arguments description store in yunohost
|
||||||
empty in CLI, filed from the admin interface)
|
|
||||||
argument_questions -- the arguments description store in yunohost
|
|
||||||
format from actions.json/toml, manifest.json/toml
|
format from actions.json/toml, manifest.json/toml
|
||||||
or config_panel.json/toml
|
or config_panel.json/toml
|
||||||
|
prefilled_answers -- a url "query-string" such as "domain=yolo.test&path=/foobar&admin=sam"
|
||||||
|
or a dict such as {"domain": "yolo.test", "path": "/foobar", "admin": "sam"}
|
||||||
"""
|
"""
|
||||||
parsed_answers_dict = OrderedDict()
|
|
||||||
|
|
||||||
for question in argument_questions:
|
if isinstance(prefilled_answers, str):
|
||||||
question_class = ARGUMENTS_TYPE_PARSERS[question.get("type", "string")]
|
# FIXME FIXME : this is not uniform with config_set() which uses parse.qs (no l)
|
||||||
question = question_class(question, user_answers)
|
# parse_qsl parse single values
|
||||||
|
# whereas parse.qs return list of values (which is useful for tags, etc)
|
||||||
|
# For now, let's not migrate this piece of code to parse_qs
|
||||||
|
# Because Aleks believes some bits of the app CI rely on overriding values (e.g. foo=foo&...&foo=bar)
|
||||||
|
answers = dict(
|
||||||
|
urllib.parse.parse_qsl(prefilled_answers or "", keep_blank_values=True)
|
||||||
|
)
|
||||||
|
elif isinstance(prefilled_answers, Mapping):
|
||||||
|
answers = {**prefilled_answers}
|
||||||
|
else:
|
||||||
|
answers = {}
|
||||||
|
|
||||||
answer = question.ask_if_needed()
|
out = []
|
||||||
if answer is not None:
|
|
||||||
parsed_answers_dict[question.name] = answer
|
|
||||||
|
|
||||||
return parsed_answers_dict
|
for raw_question in raw_questions:
|
||||||
|
question_class = ARGUMENTS_TYPE_PARSERS[raw_question.get("type", "string")]
|
||||||
|
raw_question["value"] = answers.get(raw_question["name"])
|
||||||
|
question = question_class(raw_question, context=answers)
|
||||||
|
answers[question.name] = question.ask_if_needed()
|
||||||
|
out.append(question)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
|
@ -23,6 +23,8 @@ from typing import List
|
||||||
|
|
||||||
from moulinette.utils.filesystem import read_file
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
|
SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"]
|
||||||
|
|
||||||
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
|
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
|
||||||
|
|
||||||
# Lazy dev caching to avoid re-reading the file multiple time when calling
|
# Lazy dev caching to avoid re-reading the file multiple time when calling
|
||||||
|
@ -30,6 +32,18 @@ YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
|
||||||
external_resolvers_: List[str] = []
|
external_resolvers_: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
|
def is_yunohost_dyndns_domain(domain):
|
||||||
|
|
||||||
|
return any(
|
||||||
|
domain.endswith(f".{dyndns_domain}") for dyndns_domain in YNH_DYNDNS_DOMAINS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_special_use_tld(domain):
|
||||||
|
|
||||||
|
return any(domain.endswith(f".{tld}") for tld in SPECIAL_USE_TLDS)
|
||||||
|
|
||||||
|
|
||||||
def external_resolvers():
|
def external_resolvers():
|
||||||
|
|
||||||
global external_resolvers_
|
global external_resolvers_
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import write_to_json, read_yaml
|
from moulinette.utils.filesystem import (
|
||||||
|
read_file,
|
||||||
|
write_to_file,
|
||||||
|
write_to_json,
|
||||||
|
write_to_yaml,
|
||||||
|
read_yaml,
|
||||||
|
)
|
||||||
|
|
||||||
from yunohost.user import user_list
|
from yunohost.user import user_list
|
||||||
from yunohost.app import (
|
from yunohost.app import (
|
||||||
|
@ -14,6 +23,8 @@ from yunohost.permission import (
|
||||||
user_permission_update,
|
user_permission_update,
|
||||||
permission_sync_to_user,
|
permission_sync_to_user,
|
||||||
)
|
)
|
||||||
|
from yunohost.utils.error import YunohostValidationError
|
||||||
|
|
||||||
|
|
||||||
logger = getActionLogger("yunohost.legacy")
|
logger = getActionLogger("yunohost.legacy")
|
||||||
|
|
||||||
|
@ -237,3 +248,213 @@ def translate_legacy_rules_in_ssowant_conf_json_persistent():
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"YunoHost automatically translated some legacy rules in /etc/ssowat/conf.json.persistent to match the new permission system"
|
"YunoHost automatically translated some legacy rules in /etc/ssowat/conf.json.persistent to match the new permission system"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
LEGACY_PHP_VERSION_REPLACEMENTS = [
|
||||||
|
("/etc/php5", "/etc/php/7.3"),
|
||||||
|
("/etc/php/7.0", "/etc/php/7.3"),
|
||||||
|
("/var/run/php5-fpm", "/var/run/php/php7.3-fpm"),
|
||||||
|
("/var/run/php/php7.0-fpm", "/var/run/php/php7.3-fpm"),
|
||||||
|
("php5", "php7.3"),
|
||||||
|
("php7.0", "php7.3"),
|
||||||
|
(
|
||||||
|
'phpversion="${phpversion:-7.0}"',
|
||||||
|
'phpversion="${phpversion:-7.3}"',
|
||||||
|
), # Many helpers like the composer ones use 7.0 by default ...
|
||||||
|
(
|
||||||
|
'"$phpversion" == "7.0"',
|
||||||
|
'$(bc <<< "$phpversion >= 7.3") -eq 1',
|
||||||
|
), # patch ynh_install_php to refuse installing/removing php <= 7.3
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_legacy_php_versions(app_folder):
|
||||||
|
|
||||||
|
files_to_patch = []
|
||||||
|
files_to_patch.extend(glob.glob("%s/conf/*" % app_folder))
|
||||||
|
files_to_patch.extend(glob.glob("%s/scripts/*" % app_folder))
|
||||||
|
files_to_patch.extend(glob.glob("%s/scripts/*/*" % app_folder))
|
||||||
|
files_to_patch.extend(glob.glob("%s/scripts/.*" % app_folder))
|
||||||
|
files_to_patch.append("%s/manifest.json" % app_folder)
|
||||||
|
files_to_patch.append("%s/manifest.toml" % app_folder)
|
||||||
|
|
||||||
|
for filename in files_to_patch:
|
||||||
|
|
||||||
|
# Ignore non-regular files
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
continue
|
||||||
|
|
||||||
|
c = (
|
||||||
|
"sed -i "
|
||||||
|
+ "".join(
|
||||||
|
"-e 's@{pattern}@{replace}@g' ".format(pattern=p, replace=r)
|
||||||
|
for p, r in LEGACY_PHP_VERSION_REPLACEMENTS
|
||||||
|
)
|
||||||
|
+ "%s" % filename
|
||||||
|
)
|
||||||
|
os.system(c)
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_legacy_php_versions_in_settings(app_folder):
|
||||||
|
|
||||||
|
settings = read_yaml(os.path.join(app_folder, "settings.yml"))
|
||||||
|
|
||||||
|
if settings.get("fpm_config_dir") == "/etc/php/7.0/fpm":
|
||||||
|
settings["fpm_config_dir"] = "/etc/php/7.3/fpm"
|
||||||
|
if settings.get("fpm_service") == "php7.0-fpm":
|
||||||
|
settings["fpm_service"] = "php7.3-fpm"
|
||||||
|
if settings.get("phpversion") == "7.0":
|
||||||
|
settings["phpversion"] = "7.3"
|
||||||
|
|
||||||
|
# We delete these checksums otherwise the file will appear as manually modified
|
||||||
|
list_to_remove = ["checksum__etc_php_7.0_fpm_pool", "checksum__etc_nginx_conf.d"]
|
||||||
|
settings = {
|
||||||
|
k: v
|
||||||
|
for k, v in settings.items()
|
||||||
|
if not any(k.startswith(to_remove) for to_remove in list_to_remove)
|
||||||
|
}
|
||||||
|
|
||||||
|
write_to_yaml(app_folder + "/settings.yml", settings)
|
||||||
|
|
||||||
|
|
||||||
|
def _patch_legacy_helpers(app_folder):
|
||||||
|
|
||||||
|
files_to_patch = []
|
||||||
|
files_to_patch.extend(glob.glob("%s/scripts/*" % app_folder))
|
||||||
|
files_to_patch.extend(glob.glob("%s/scripts/.*" % app_folder))
|
||||||
|
|
||||||
|
stuff_to_replace = {
|
||||||
|
# Replace
|
||||||
|
# sudo yunohost app initdb $db_user -p $db_pwd
|
||||||
|
# by
|
||||||
|
# ynh_mysql_setup_db --db_user=$db_user --db_name=$db_user --db_pwd=$db_pwd
|
||||||
|
"yunohost app initdb": {
|
||||||
|
"pattern": r"(sudo )?yunohost app initdb \"?(\$\{?\w+\}?)\"?\s+-p\s\"?(\$\{?\w+\}?)\"?",
|
||||||
|
"replace": r"ynh_mysql_setup_db --db_user=\2 --db_name=\2 --db_pwd=\3",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# Replace
|
||||||
|
# sudo yunohost app checkport whaterver
|
||||||
|
# by
|
||||||
|
# ynh_port_available whatever
|
||||||
|
"yunohost app checkport": {
|
||||||
|
"pattern": r"(sudo )?yunohost app checkport",
|
||||||
|
"replace": r"ynh_port_available",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# We can't migrate easily port-available
|
||||||
|
# .. but at the time of writing this code, only two non-working apps are using it.
|
||||||
|
"yunohost tools port-available": {"important": True},
|
||||||
|
# Replace
|
||||||
|
# yunohost app checkurl "${domain}${path_url}" -a "${app}"
|
||||||
|
# by
|
||||||
|
# ynh_webpath_register --app=${app} --domain=${domain} --path_url=${path_url}
|
||||||
|
"yunohost app checkurl": {
|
||||||
|
"pattern": r"(sudo )?yunohost app checkurl \"?(\$\{?\w+\}?)\/?(\$\{?\w+\}?)\"?\s+-a\s\"?(\$\{?\w+\}?)\"?",
|
||||||
|
"replace": r"ynh_webpath_register --app=\4 --domain=\2 --path_url=\3",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# Remove
|
||||||
|
# Automatic diagnosis data from YunoHost
|
||||||
|
# __PRE_TAG1__$(yunohost tools diagnosis | ...)__PRE_TAG2__"
|
||||||
|
#
|
||||||
|
"yunohost tools diagnosis": {
|
||||||
|
"pattern": r"(Automatic diagnosis data from YunoHost( *\n)*)? *(__\w+__)? *\$\(yunohost tools diagnosis.*\)(__\w+__)?",
|
||||||
|
"replace": r"",
|
||||||
|
"important": False,
|
||||||
|
},
|
||||||
|
# Old $1, $2 in backup/restore scripts...
|
||||||
|
"app=$2": {
|
||||||
|
"only_for": ["scripts/backup", "scripts/restore"],
|
||||||
|
"pattern": r"app=\$2",
|
||||||
|
"replace": r"app=$YNH_APP_INSTANCE_NAME",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# Old $1, $2 in backup/restore scripts...
|
||||||
|
"backup_dir=$1": {
|
||||||
|
"only_for": ["scripts/backup", "scripts/restore"],
|
||||||
|
"pattern": r"backup_dir=\$1",
|
||||||
|
"replace": r"backup_dir=.",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# Old $1, $2 in backup/restore scripts...
|
||||||
|
"restore_dir=$1": {
|
||||||
|
"only_for": ["scripts/restore"],
|
||||||
|
"pattern": r"restore_dir=\$1",
|
||||||
|
"replace": r"restore_dir=.",
|
||||||
|
"important": True,
|
||||||
|
},
|
||||||
|
# Old $1, $2 in install scripts...
|
||||||
|
# We ain't patching that shit because it ain't trivial to patch all args...
|
||||||
|
"domain=$1": {"only_for": ["scripts/install"], "important": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
for helper, infos in stuff_to_replace.items():
|
||||||
|
infos["pattern"] = (
|
||||||
|
re.compile(infos["pattern"]) if infos.get("pattern") else None
|
||||||
|
)
|
||||||
|
infos["replace"] = infos.get("replace")
|
||||||
|
|
||||||
|
for filename in files_to_patch:
|
||||||
|
|
||||||
|
# Ignore non-regular files
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
content = read_file(filename)
|
||||||
|
except MoulinetteError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
replaced_stuff = False
|
||||||
|
show_warning = False
|
||||||
|
|
||||||
|
for helper, infos in stuff_to_replace.items():
|
||||||
|
|
||||||
|
# Ignore if not relevant for this file
|
||||||
|
if infos.get("only_for") and not any(
|
||||||
|
filename.endswith(f) for f in infos["only_for"]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If helper is used, attempt to patch the file
|
||||||
|
if helper in content and infos["pattern"]:
|
||||||
|
content = infos["pattern"].sub(infos["replace"], content)
|
||||||
|
replaced_stuff = True
|
||||||
|
if infos["important"]:
|
||||||
|
show_warning = True
|
||||||
|
|
||||||
|
# If the helper is *still* in the content, it means that we
|
||||||
|
# couldn't patch the deprecated helper in the previous lines. In
|
||||||
|
# that case, abort the install or whichever step is performed
|
||||||
|
if helper in content and infos["important"]:
|
||||||
|
raise YunohostValidationError(
|
||||||
|
"This app is likely pretty old and uses deprecated / outdated helpers that can't be migrated easily. It can't be installed anymore.",
|
||||||
|
raw_msg=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if replaced_stuff:
|
||||||
|
|
||||||
|
# Check the app do load the helper
|
||||||
|
# If it doesn't, add the instruction ourselve (making sure it's after the #!/bin/bash if it's there...
|
||||||
|
if filename.split("/")[-1] in [
|
||||||
|
"install",
|
||||||
|
"remove",
|
||||||
|
"upgrade",
|
||||||
|
"backup",
|
||||||
|
"restore",
|
||||||
|
]:
|
||||||
|
source_helpers = "source /usr/share/yunohost/helpers"
|
||||||
|
if source_helpers not in content:
|
||||||
|
content.replace("#!/bin/bash", "#!/bin/bash\n" + source_helpers)
|
||||||
|
if source_helpers not in content:
|
||||||
|
content = source_helpers + "\n" + content
|
||||||
|
|
||||||
|
# Actually write the new content in the file
|
||||||
|
write_to_file(filename, content)
|
||||||
|
|
||||||
|
if show_warning:
|
||||||
|
# And complain about those damn deprecated helpers
|
||||||
|
logger.error(
|
||||||
|
r"/!\ Packagers ! This app uses a very old deprecated helpers ... Yunohost automatically patched the helpers to use the new recommended practice, but please do consider fixing the upstream code right now ..."
|
||||||
|
)
|
||||||
|
|
92
tests/test_helpers.d/ynhtest_logging.sh
Normal file
92
tests/test_helpers.d/ynhtest_logging.sh
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
ynhtest_exec_warn_less() {
|
||||||
|
|
||||||
|
FOO='foo'
|
||||||
|
bar=""
|
||||||
|
BAR='$bar'
|
||||||
|
FOOBAR="foo bar"
|
||||||
|
|
||||||
|
# These looks like stupid edge case
|
||||||
|
# but in fact happens when dealing with passwords
|
||||||
|
# (which could also contain bash chars like [], {}, ...)
|
||||||
|
# or urls containing &, ...
|
||||||
|
FOOANDBAR="foo&bar"
|
||||||
|
FOO1QUOTEBAR="foo'bar"
|
||||||
|
FOO2QUOTEBAR="foo\"bar"
|
||||||
|
|
||||||
|
ynh_exec_warn_less uptime
|
||||||
|
|
||||||
|
test ! -e $FOO
|
||||||
|
ynh_exec_warn_less touch $FOO
|
||||||
|
test -e $FOO
|
||||||
|
rm $FOO
|
||||||
|
|
||||||
|
test ! -e $FOO1QUOTEBAR
|
||||||
|
ynh_exec_warn_less touch $FOO1QUOTEBAR
|
||||||
|
test -e $FOO1QUOTEBAR
|
||||||
|
rm $FOO1QUOTEBAR
|
||||||
|
|
||||||
|
test ! -e $FOO2QUOTEBAR
|
||||||
|
ynh_exec_warn_less touch $FOO2QUOTEBAR
|
||||||
|
test -e $FOO2QUOTEBAR
|
||||||
|
rm $FOO2QUOTEBAR
|
||||||
|
|
||||||
|
test ! -e $BAR
|
||||||
|
ynh_exec_warn_less touch $BAR
|
||||||
|
test -e $BAR
|
||||||
|
rm $BAR
|
||||||
|
|
||||||
|
test ! -e "$FOOBAR"
|
||||||
|
ynh_exec_warn_less touch "$FOOBAR"
|
||||||
|
test -e "$FOOBAR"
|
||||||
|
rm "$FOOBAR"
|
||||||
|
|
||||||
|
test ! -e "$FOOANDBAR"
|
||||||
|
ynh_exec_warn_less touch $FOOANDBAR
|
||||||
|
test -e "$FOOANDBAR"
|
||||||
|
rm "$FOOANDBAR"
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Legacy stuff using eval #
|
||||||
|
###########################
|
||||||
|
|
||||||
|
test ! -e $FOO
|
||||||
|
ynh_exec_warn_less "touch $FOO"
|
||||||
|
test -e $FOO
|
||||||
|
rm $FOO
|
||||||
|
|
||||||
|
test ! -e $FOO1QUOTEBAR
|
||||||
|
ynh_exec_warn_less "touch \"$FOO1QUOTEBAR\""
|
||||||
|
# (this works but expliciy *double* quotes have to be provided)
|
||||||
|
test -e $FOO1QUOTEBAR
|
||||||
|
rm $FOO1QUOTEBAR
|
||||||
|
|
||||||
|
#test ! -e $FOO2QUOTEBAR
|
||||||
|
#ynh_exec_warn_less "touch \'$FOO2QUOTEBAR\'"
|
||||||
|
## (this doesn't work with simple or double quotes)
|
||||||
|
#test -e $FOO2QUOTEBAR
|
||||||
|
#rm $FOO2QUOTEBAR
|
||||||
|
|
||||||
|
test ! -e $BAR
|
||||||
|
ynh_exec_warn_less 'touch $BAR'
|
||||||
|
# That one works because $BAR is only interpreted during eval
|
||||||
|
test -e $BAR
|
||||||
|
rm $BAR
|
||||||
|
|
||||||
|
#test ! -e $BAR
|
||||||
|
#ynh_exec_warn_less "touch $BAR"
|
||||||
|
# That one doesn't work because $bar gets interpreted as empty var by eval...
|
||||||
|
#test -e $BAR
|
||||||
|
#rm $BAR
|
||||||
|
|
||||||
|
test ! -e "$FOOBAR"
|
||||||
|
ynh_exec_warn_less "touch \"$FOOBAR\""
|
||||||
|
# (works but requires explicit double quotes otherwise eval would interpret 'foo bar' as two separate args..)
|
||||||
|
test -e "$FOOBAR"
|
||||||
|
rm "$FOOBAR"
|
||||||
|
|
||||||
|
test ! -e "$FOOANDBAR"
|
||||||
|
ynh_exec_warn_less "touch \"$FOOANDBAR\""
|
||||||
|
# (works but requires explicit double quotes otherwise eval would interpret '&' as a "run command in background" and also bar is not a valid command)
|
||||||
|
test -e "$FOOANDBAR"
|
||||||
|
rm "$FOOANDBAR"
|
||||||
|
}
|
71
tests/test_helpers.d/ynhtest_secure_remove.sh
Normal file
71
tests/test_helpers.d/ynhtest_secure_remove.sh
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
ynhtest_acceptable_path_to_delete() {
|
||||||
|
|
||||||
|
mkdir -p /home/someuser
|
||||||
|
mkdir -p /home/$app
|
||||||
|
mkdir -p /home/yunohost.app/$app
|
||||||
|
mkdir -p /var/www/$app
|
||||||
|
touch /var/www/$app/bar
|
||||||
|
touch /etc/cron.d/$app
|
||||||
|
|
||||||
|
! _acceptable_path_to_delete /
|
||||||
|
! _acceptable_path_to_delete ////
|
||||||
|
! _acceptable_path_to_delete " //// "
|
||||||
|
! _acceptable_path_to_delete /var
|
||||||
|
! _acceptable_path_to_delete /var/www
|
||||||
|
! _acceptable_path_to_delete /var/cache
|
||||||
|
! _acceptable_path_to_delete /usr
|
||||||
|
! _acceptable_path_to_delete /usr/bin
|
||||||
|
! _acceptable_path_to_delete /home
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.backup
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.app
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.app/
|
||||||
|
! _acceptable_path_to_delete ///home///yunohost.app///
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.app/$app/..
|
||||||
|
! _acceptable_path_to_delete ///home///yunohost.app///$app///..//
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.app/../$app/..
|
||||||
|
! _acceptable_path_to_delete /home/someuser
|
||||||
|
! _acceptable_path_to_delete /home/yunohost.app//../../$app
|
||||||
|
! _acceptable_path_to_delete " /home/yunohost.app/// "
|
||||||
|
! _acceptable_path_to_delete /etc/cron.d/
|
||||||
|
! _acceptable_path_to_delete /etc/yunohost/
|
||||||
|
|
||||||
|
_acceptable_path_to_delete /home/yunohost.app/$app
|
||||||
|
_acceptable_path_to_delete /home/yunohost.app/$app/bar
|
||||||
|
_acceptable_path_to_delete /etc/cron.d/$app
|
||||||
|
_acceptable_path_to_delete /var/www/$app/bar
|
||||||
|
_acceptable_path_to_delete /var/www/$app
|
||||||
|
|
||||||
|
rm /var/www/$app/bar
|
||||||
|
rm /etc/cron.d/$app
|
||||||
|
rmdir /home/yunohost.app/$app
|
||||||
|
rmdir /home/$app
|
||||||
|
rmdir /home/someuser
|
||||||
|
rmdir /var/www/$app
|
||||||
|
}
|
||||||
|
|
||||||
|
ynhtest_secure_remove() {
|
||||||
|
|
||||||
|
mkdir -p /home/someuser
|
||||||
|
mkdir -p /home/yunohost.app/$app
|
||||||
|
mkdir -p /var/www/$app
|
||||||
|
mkdir -p /var/whatever
|
||||||
|
touch /var/www/$app/bar
|
||||||
|
touch /etc/cron.d/$app
|
||||||
|
|
||||||
|
! ynh_secure_remove --file="/home/someuser"
|
||||||
|
! ynh_secure_remove --file="/home/yunohost.app/"
|
||||||
|
! ynh_secure_remove --file="/var/whatever"
|
||||||
|
ynh_secure_remove --file="/home/yunohost.app/$app"
|
||||||
|
ynh_secure_remove --file="/var/www/$app"
|
||||||
|
ynh_secure_remove --file="/etc/cron.d/$app"
|
||||||
|
|
||||||
|
test -e /home/someuser
|
||||||
|
test -e /home/yunohost.app
|
||||||
|
test -e /var/whatever
|
||||||
|
! test -e /home/yunohost.app/$app
|
||||||
|
! test -e /var/www/$app
|
||||||
|
! test -e /etc/cron.d/$app
|
||||||
|
|
||||||
|
rmdir /home/someuser
|
||||||
|
rmdir /var/whatever
|
||||||
|
}
|
2
tox.ini
2
tox.ini
|
@ -9,7 +9,7 @@ deps =
|
||||||
py37-mypy: mypy >= 0.900
|
py37-mypy: mypy >= 0.900
|
||||||
commands =
|
commands =
|
||||||
py37-lint: flake8 src doc data tests --ignore E402,E501,E203,W503 --exclude src/yunohost/vendor
|
py37-lint: flake8 src doc data tests --ignore E402,E501,E203,W503 --exclude src/yunohost/vendor
|
||||||
py37-invalidcode: flake8 src data --exclude src/yunohost/tests,src/yunohost/vendor --select F
|
py37-invalidcode: flake8 src data --exclude src/yunohost/tests,src/yunohost/vendor --select F,E722,W605
|
||||||
py37-black-check: black --check --diff src doc data tests
|
py37-black-check: black --check --diff src doc data tests
|
||||||
py37-black-run: black src doc data tests
|
py37-black-run: black src doc data tests
|
||||||
py37-mypy: mypy --ignore-missing-import --install-types --non-interactive --follow-imports silent src/yunohost/ --exclude (acme_tiny|data_migrations)
|
py37-mypy: mypy --ignore-missing-import --install-types --non-interactive --follow-imports silent src/yunohost/ --exclude (acme_tiny|data_migrations)
|
||||||
|
|
Loading…
Add table
Reference in a new issue