From d8e693805055dc43956c7ac47e58956951326497 Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Fri, 9 Jun 2017 14:03:32 +0200 Subject: [PATCH] First commit --- .gitignore | 2 + LICENSE | 21 ++ README.md | 8 + conf/minetest.conf | 193 ++++++++++++++ conf/minetest.list | 1 + manifest.json | 71 +++++ scripts/_common.sh | 626 +++++++++++++++++++++++++++++++++++++++++++++ scripts/install | 99 +++++++ scripts/remove | 51 ++++ 9 files changed, 1072 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 conf/minetest.conf create mode 100644 conf/minetest.list create mode 100644 manifest.json create mode 100644 scripts/_common.sh create mode 100755 scripts/install create mode 100755 scripts/remove diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..783a4ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +*.sw[op] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..936dee3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Framasoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e98baf2 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Minetest app for YunoHost + +- [Yunohost project](https://yunohost.org) +- [Minetest website](http://www.minetest.net/) + +![alt text](http://www.minetest.net/media/icon.svg "Minetest logo") Minetest +=== +Minetest is a free, open source voxel game engine and game. Fully extendable. You are in control. diff --git a/conf/minetest.conf b/conf/minetest.conf new file mode 100644 index 0000000..e19a68c --- /dev/null +++ b/conf/minetest.conf @@ -0,0 +1,193 @@ +# configuration file for minetestserver + +# Admin name +#name = + +# Server stuff +# Network port to listen (UDP) +port = __PORT__ + +# Bind address +#bind_address = 123.123.123.123 + +# Name of server +server_name = My Minetest server + +# Description of server +server_description = Minetest server powered by Debian and YuNoHost + +# Domain name of server +#server_address = __DOMAIN__ + +# Homepage of server +#server_url = http://example.com + +# Automaticaly report to masterserver +# set to true for public servers +server_announce = __ANNOUNCE__ + +# Announce to this masterserver. if you want to announce your ipv6 address +# use serverlist_url = v6.servers.minetest.net + +# Enable/disable running an IPv6 server. An IPv6 server may be +# restricted to IPv6 clients, depending on system configuration. +# Ignored if bind_address is set. +# type: bool +# ipv6_server = false + +serverlist_url = servers.minetest.net + +# Default game (default when creating a new world) +default_game = minetest + +# World directory (everything in the world is stored here) +#map-dir = /var/games/minetest-server/.minetest/worlds/world + +# Message of the Day +motd = Welcome to Minetest. Enjoy your stay! + +# Maximum number of players connected simultaneously +max_users = 15 + +# Whether to enable players killing each other +enable_pvp = __PVP__ + +# Set to true to enable creative mode (unlimited inventory) +creative_mode = __CREATIVE__ + +# Enable players getting damage and dying +enable_damage = __DAMAGE__ + +# Available privileges: interact, shout, teleport, settime, privs, ... +# See /privs in game for a full list on your server and mod configuration. +default_privs = interact, shout + +# Set to true to disallow old clients from connecting +#strict_protocol_version_checking = false + +# Time in seconds for item entity to live. Default value: 900s +# Setting it to -1 disables the feature +#item_entity_ttl = 900 + +# Despawn all non-peaceful mobs +#only_peaceful_mobs = false + +# A chosen map seed for a new map, leave empty for random +#fixed_map_seed = + +# Gives some stuff to players at the beginning +#give_initial_stuff = false + +# New users need to input this password +#default_password = + +# Whether players are shown to clients without any range limit +#unlimited_player_transfer_distance = true + +# If this is set, players will always (re)spawn at the given position +#static_spawnpoint = 0, 10, 0 + +# If true, new players cannot join with an empty password +#disallow_empty_password = false + +# If true, disable cheat prevention in multiplayer +#disable_anticheat = false + +# If true, actions are recorded for rollback +#enable_rollback_recording = false + +# handling for deprecated lua api calls +# "legacy" = (try to) mimic old behaviour (default for release) +# "log" = mimic and log backtrace of deprecated call (default for debug) +# "error" = abort on usage of deprecated call (suggested for mod developers) +#deprecated_lua_api_handling = legacy + +# Profiler data print interval. #0 = disable. +#profiler_print_interval = 0 + +#enable_mapgen_debug_info = false +# from how far client knows about objects +#active_object_send_range_blocks = 3 + +# how large area of blocks are subject to the active block stuff (active = objects are loaded and ABMs run) +#active_block_range = 2 + +# how many blocks are flying in the wire simultaneously per client +#max_simultaneous_block_sends_per_client = 10 + +# how many blocks are flying in the wire simultaneously per server +#max_simultaneous_block_sends_server_total = 40 + +# From how far blocks are sent to clients (value * 16 nodes) +#max_block_send_distance = 10 + +# From how far blocks are generated for clients (value * 16 nodes) +#max_block_generate_distance = 6 + +# Number of extra blocks that can be loaded by /clearobjects at once +# This is a trade-off between sqlite transaction overhead and +# memory consumption (4096=100MB, as a rule of thumb) +#max_clearobjects_extra_loaded_blocks = 4096 + +# Maximum number of forceloaded blocks +#max_forceloaded_blocks = 16 + +# Interval of sending time of day to clients +#time_send_interval = 5 + +# Length of day/night cycle. 72=20min, 360=4min, 1=24hour, 0=day/night/whatever stays unchanged +#time_speed = 72 + +# Length of year in days for seasons change. With default time_speed 365 days = 5 real days for year. 30 days = 10 real hours +#year_days = 30 + +#server_unload_unused_data_timeout = 29 + +# Maximum number of statically stored objects in a block +#max_objects_per_block = 49 + +# Interval of saving important changes in the world + +#server_map_save_interval = 5.3 +# http://www.sqlite.org/pragma.html#pragma_synchronous only numeric values: 0 1 2 +#sqlite_synchronous = 2 +# To reduce lag, block transfers are slowed down when a player is building something. +# This determines how long they are slowed down after placing or removing a node. +#full_block_send_enable_min_time_from_building = 2.0 + +# Length of a server tick and the interval at which objects are generally updated over network +#dedicated_server_step = 0.1 + +# Can be set to true to disable shutting down on invalid world data +#ignore_world_load_errors = false + +# Specifies URL from which client fetches media instead of using UDP +# $filename should be accessible from $remote_media$filename via cURL +# (obviously, remote_media should end with a slash) + +# Files that are not present would be fetched the usual way +#remote_media = + +# Level of logging to be written to debug.txt. +# 0 = none, 1 = errors and debug, 2 = action, 3 = info, 4 = verbose +#debug_log_level = 2 + +# Maximum number of blocks that can be queued for loading. +#emergequeue_limit_total = 256 + +# Maximum number of blocks to be queued that are to be loaded from file. +# Set to blank for an appropriate amount to be chosen automatically. +#emergequeue_limit_diskonly = 32 + +# Maximum number of blocks to be queued that are to be generated. +# Set to blank for an appropriate amount to be chosen automatically. +#emergequeue_limit_generate = 32 + +# Number of emerge threads to use. Make this field blank, or increase this number, to use multiple threads. +# On multiprocessor systems, this will improve mapgen speed greatly, at the cost of slightly buggy caves. +#num_emerge_threads = 1 + +# maximum number of packets sent per send step, if you have a slow connection +# try reducing it, but don't reduce it to a number below double of targeted +# client number +#max_packets_per_iteration = 1024 diff --git a/conf/minetest.list b/conf/minetest.list new file mode 100644 index 0000000..73dfaf0 --- /dev/null +++ b/conf/minetest.list @@ -0,0 +1 @@ +deb http://http.debian.net/debian __CODENAME__-backports main diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..5115269 --- /dev/null +++ b/manifest.json @@ -0,0 +1,71 @@ +{ + "name": "Minetest", + "id": "minetest", + "packaging_format": 1, + "description": { + "en": "Minetest is a free, open source voxel game engine and game. Fully extendable. Need a client to connect to the server.", + "fr": "Minetest est un moteur de jeu de type « bac à sable » gratuit et open source. Entièrement extensible. Nécessite un client pour se connecter au serveur." + }, + "url": "http://www.minetest.net/", + "license": "MIT", + "maintainer": { + "name": "Luc Didry", + "email": "luc@framasoft.org", + "url": "https://framasoft.org" + }, + "requirements": { + "yunohost": ">> 2.4.0" + }, + "multi_instance": true, + "services": [ + ], + "arguments": { + "install" : [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain for your minetest server", + "fr": "Choisissez un domaine pour votre serveur minetest" + }, + "example": "domain.org" + }, + { + "name": "is_public", + "type": "boolean", + "ask": { + "en": "Is it a public server? (should we announce it?)", + "fr": "Est-ce un serveur public ? (devons-nous l'annoncer ?)" + }, + "default": false + }, + { + "name": "pvp", + "type": "boolean", + "ask": { + "en": "Whether to enable players killing each other", + "fr": "Permettre aux joueurs de se tuer l'un l'autre" + }, + "default": false + }, + { + "name": "creative", + "type": "boolean", + "ask": { + "en": "Whether to enable creative mode (unlimited inventory)", + "fr": "Permettre l'utilisation du mode créatif (inventaire illimité" + }, + "default": false + }, + { + "name": "damage", + "type": "boolean", + "ask": { + "en": "Enable players getting damage and dying", + "fr": "Les joueurs pourront-ils recevoir des dommages et mourir ?" + }, + "default": true + } + ] + } +} diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..108271c --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,626 @@ +#!/bin/bash + +#================================================= +#================================================= +# TESTING +#================================================= +#================================================= + +# Remove a file or a directory securely +# +# usage: ynh_secure_remove path_to_remove +# | arg: path_to_remove - File or directory to remove +ynh_secure_remove () { + path_to_remove=$1 + forbidden_path=" \ + /var/www \ + /home/yunohost.app" + + if [[ "$forbidden_path" =~ "$path_to_remove" \ + # Match all path or subpath in $forbidden_path + || "$path_to_remove" =~ ^/[[:alnum:]]+$ \ + # Match all first level path from / (Like /var, /root, etc...) + || "${path_to_remove:${#path_to_remove}-1}" = "/" ]] + # Match if the path finish by /. Because it's seems there is an empty variable + then + echo "Avoid deleting of $path_to_remove." >&2 + else + if [ -e "$path_to_remove" ] + then + sudo rm -R "$path_to_remove" + else + echo "$path_to_remove doesn't deleted because it's not exist." >&2 + fi + fi +} + +ynh_setup_source () { + src_url=$(cat ../conf/app.src | grep SOURCE_URL | cut -d= -f2-) + src_checksum=$(cat ../conf/app.src | grep SOURCE_SUM | cut -d= -f2-) + arch_format=$(cat ../conf/app.src | grep ARCH_FORMAT | cut -d= -f2-) + local_source="/opt/yunohost-apps-src/$YNH_APP_ID/source.$arch_format" + + if test -e "$local_source" + then # Use the local source file if it is present + cp $local_source source.$arch_format + else # If not, download the source + wget -nv -O source.$arch_format $src_url + fi + + # Check the control sum + echo "$src_checksum source.$arch_format" \ + | md5sum -c --status || ynh_die "Corrupt source" + + # Extract source into the app dir + sudo mkdir -p "$final_path" + if [ $(echo "$arch_format" | tr '[:upper:]' '[:lower:]') = "zip" ] + then # Zip format + # Using of a temp directory, because unzip doesn't manage --strip-components + temp_dir=$(mktemp -d) + unzip -quo source.zip -d "$temp_dir" + sudo cp -a $temp_dir/*/. "$final_path" + ynh_secure_remove "$temp_dir" + elif [ $(echo "$arch_format" | tr '[:upper:]' '[:lower:]') = "tar.gz" ]; then + sudo tar -x -f source.tar.gz -C "$final_path" --strip-components 1 + else + ynh_die "Format d'archive non reconnu." + fi + + # Apply patches + if test -f ../sources/patches/*.patch; then + (cd "$DEST" \ + && for p in ${PKG_DIR}/patches/*.patch; do \ + sudo patch -p1 < $p; done) \ + || ynh_die "Unable to apply patches" + fi + + # Add supplementary files + if test -e "../sources/extra_files"; then + sudo cp -a ../sources/extra_files/. "$final_path" + fi +} + +ynh_backup_abstract () { + # A intégrer à ynh_backup directement. + ynh_backup "$@" + echo "$2" "$1" >> backup_list +} + +ynh_restore_file () { + file_and_dest=$(grep "^$1" backup_list) + backup_file=${file_and_dest%% *} + backup_dest=${file_and_dest#* } + if [ -f "$backup_dest" ]; then + ynh_die "There is already a file at this path: $backup_dest" + fi + if test -d "$backup_file"; then + sudo cp -a "$backup_file/." "$backup_dest" + else + sudo cp -a "$backup_file" "$backup_dest" + fi +} + +ynh_fpm_config () { + finalphpconf="/etc/php5/fpm/pool.d/$app.conf" + ynh_compare_checksum_config "$finalphpconf" 1 + sudo cp ../conf/php-fpm.conf "$finalphpconf" + ynh_replace_string "__NAMETOCHANGE__" "$app" "$finalphpconf" + ynh_replace_string "__FINALPATH__" "$final_path" "$finalphpconf" + ynh_replace_string "__USER__" "$app" "$finalphpconf" + sudo chown root: "$finalphpconf" + ynh_store_checksum_config "$finalphpconf" + + if [ -e "../conf/php-fpm.ini" ] + then + finalphpini="/etc/php5/fpm/conf.d/20-$app.ini" + ynh_compare_checksum_config "$finalphpini" 1 + sudo cp ../conf/php-fpm.ini "$finalphpini" + sudo chown root: "$finalphpini" + ynh_store_checksum_config "$finalphpini" + fi + + sudo systemctl reload php5-fpm +} + +ynh_remove_fpm_config () { + ynh_secure_remove "/etc/php5/fpm/pool.d/$app.conf" + ynh_secure_remove "/etc/php5/fpm/conf.d/20-$app.ini" + sudo systemctl reload php5-fpm +} + +ynh_nginx_config () { + finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" + ynh_compare_checksum_config "$finalnginxconf" 1 + sudo cp ../conf/nginx.conf "$finalnginxconf" + + # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. + # Substitute in a nginx config file only if the variable is not empty + if test -n "${path_url:-}"; then + ynh_replace_string "__PATH__" "$path_url" "$finalnginxconf" + fi + if test -n "${domain:-}"; then + ynh_replace_string "__DOMAIN__" "$domain" "$finalnginxconf" + fi + if test -n "${port:-}"; then + ynh_replace_string "__PORT__" "$port" "$finalnginxconf" + fi + if test -n "${app:-}"; then + ynh_replace_string "__NAME__" "$app" "$finalnginxconf" + fi + if test -n "${final_path:-}"; then + ynh_replace_string "__FINALPATH__" "$final_path" "$finalnginxconf" + fi + ynh_store_checksum_config "$finalnginxconf" + + sudo systemctl reload nginx +} + +ynh_remove_nginx_config () { + ynh_secure_remove "/etc/nginx/conf.d/$domain.d/$app.conf" + sudo systemctl reload nginx +} + +ynh_store_checksum_config () { + config_file_checksum=checksum_${1//[\/ ]/_} # Replace all '/' and ' ' by '_' + ynh_app_setting_set $app $config_file_checksum $(sudo md5sum "$1" | cut -d' ' -f1) +} + +ynh_compare_checksum_config () { + current_config_file=$1 + compress_backup=${2:-0} # If $2 is empty, compress_backup will set at 0 + config_file_checksum=checksum_${current_config_file//[\/ ]/_} # Replace all '/' and ' ' by '_' + checksum_value=$(ynh_app_setting_get $app $config_file_checksum) + if [ -n "$checksum_value" ] + then # Proceed only if a value was stocked into the app config + if ! echo "$checksum_value $current_config_file" | sudo md5sum -c --status + then # If the checksum is now different + backup_config_file="$current_config_file.backup.$(date '+%d.%m.%y_%Hh%M,%Ss')" + if [ $compress_backup -eq 1 ] + then + sudo tar --create --gzip --file "$backup_config_file.tar.gz" "$current_config_file" # Backup the current config file and compress + backup_config_file="$backup_config_file.tar.gz" + else + sudo cp -a "$current_config_file" "$backup_config_file" # Backup the current config file + fi + echo "Config file $current_config_file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_config_file" >&2 + echo "$backup_config_file" # Return the name of the backup file + fi + fi +} + +ynh_systemd_config () { + finalsystemdconf="/etc/systemd/system/$app.service" + ynh_compare_checksum_config "$finalsystemdconf" 1 + sudo cp ../conf/systemd.service "$finalsystemdconf" + + # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. + # Substitute in a nginx config file only if the variable is not empty + if test -n "${final_path:-}"; then + ynh_replace_string "__FINALPATH__" "$final_path" "$finalsystemdconf" + fi + if test -n "${app:-}"; then + ynh_replace_string "__APP__" "$app" "$finalsystemdconf" + fi + ynh_store_checksum_config "$finalsystemdconf" + + sudo chown root: "$finalsystemdconf" + sudo systemctl enable $app + sudo systemctl daemon-reload +} + +ynh_remove_systemd_config () { + finalsystemdconf="/etc/systemd/system/$app.service" + if [ -e "$finalsystemdconf" ]; then + sudo systemctl stop $app + sudo systemctl disable $app + ynh_secure_remove "$finalsystemdconf" + fi +} + +#================================================= +#================================================= + +#================================================= +# CHECKING +#================================================= + +CHECK_DOMAINPATH () { # Vérifie la disponibilité du path et du domaine. + sudo yunohost app checkurl $domain$path_url -a $app +} + +CHECK_FINALPATH () { # Vérifie que le dossier de destination n'est pas déjà utilisé. + final_path=/var/www/$app + test ! -e "$final_path" || ynh_die "This path already contains a folder" +} + +#================================================= +# DISPLAYING +#================================================= + +NO_PRINT () { # Supprime l'affichage dans stdout pour la commande en argument. + set +x + $@ + set -x +} + +WARNING () { # Écrit sur le canal d'erreur pour passer en warning. + $@ >&2 +} + +SUPPRESS_WARNING () { # Force l'écriture sur la sortie standard + $@ 2>&1 +} + +QUIET () { # Redirige la sortie standard dans /dev/null + $@ > /dev/null +} + +ALL_QUIET () { # Redirige la sortie standard et d'erreur dans /dev/null + $@ > /dev/null 2>&1 +} + +#================================================= +# BACKUP +#================================================= + +BACKUP_FAIL_UPGRADE () { + WARNING echo "Upgrade failed." + app_bck=${app//_/-} # Replace all '_' by '-' + if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number; then # Vérifie l'existence de l'archive avant de supprimer l'application et de restaurer + sudo yunohost app remove $app # Supprime l'application avant de la restaurer. + sudo yunohost backup restore --ignore-hooks $app_bck-pre-upgrade$backup_number --apps $app --force # Restore the backup if upgrade failed + ynh_die "The app was restored to the way it was before the failed upgrade." + fi +} + +BACKUP_BEFORE_UPGRADE () { # Backup the current version of the app, restore it if the upgrade fails + backup_number=1 + old_backup_number=2 + app_bck=${app//_/-} # Replace all '_' by '-' + if sudo yunohost backup list | grep -q $app_bck-pre-upgrade1; then # Vérifie l'existence d'une archive déjà numéroté à 1. + backup_number=2 # Et passe le numéro de l'archive à 2 + old_backup_number=1 + fi + + sudo yunohost backup create --ignore-hooks --apps $app --name $app_bck-pre-upgrade$backup_number # Créer un backup différent de celui existant. + if [ "$?" -eq 0 ]; then # Si le backup est un succès, supprime l'archive précédente. + if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number; then # Vérifie l'existence de l'ancienne archive avant de la supprimer, pour éviter une erreur. + QUIET sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number + fi + else # Si le backup a échoué + ynh_die "Backup failed, the upgrade process was aborted." + fi +} + +HUMAN_SIZE () { # Transforme une taille en Ko en une taille lisible pour un humain + human=$(numfmt --to=iec --from-unit=1K $1) + echo $human +} + +CHECK_SIZE () { # Vérifie avant chaque backup que l'espace est suffisant + file_to_analyse=$1 + backup_size=$(sudo du --summarize "$file_to_analyse" | cut -f1) + free_space=$(sudo df --output=avail "/home/yunohost.backup" | sed 1d) + + if [ $free_space -le $backup_size ] + then + WARNING echo "Espace insuffisant pour sauvegarder $file_to_analyse." + WARNING echo "Espace disponible: $(HUMAN_SIZE $free_space)" + ynh_die "Espace nécessaire: $(HUMAN_SIZE $backup_size)" + fi +} + +#================================================= +# PACKAGE CHECK BYPASSING... +#================================================= + +IS_PACKAGE_CHECK () { # Détermine une exécution en conteneur (Non testé) + return $(uname -n | grep -c 'pchecker_lxc') +} + +#================================================= +#================================================= +# FUTUR YNH HELPERS +#================================================= +# Importer ce fichier de fonction avant celui des helpers officiel +# Ainsi, les officiels prendront le pas sur ceux-ci le cas échéant +#================================================= + +# Normalize the url path syntax +# Handle the slash at the beginning of path and its absence at ending +# Return a normalized url path +# +# example: url_path=$(ynh_normalize_url_path $url_path) +# ynh_normalize_url_path example -> /example +# ynh_normalize_url_path /example -> /example +# ynh_normalize_url_path /example/ -> /example +# ynh_normalize_url_path / -> / +# +# usage: ynh_normalize_url_path path_to_normalize +# | arg: url_path_to_normalize - URL path to normalize before using it +ynh_normalize_url_path () { + path_url=$1 + test -n "$path_url" || ynh_die "ynh_normalize_url_path expect a URL path as first argument and received nothing." + if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a / + path_url="/$path_url" # Add / at begin of path variable + fi + if [ "${path_url:${#path_url}-1}" == "/" ] && [ ${#path_url} -gt 1 ]; then # If the last character is a / and that not the only character. + path_url="${path_url:0:${#path_url}-1}" # Delete the last character + fi + echo $path_url +} + +# Create a database, an user and its password. Then store the password in the app's config +# +# User of database will be store in db_user's variable. +# Name of database will be store in db_name's variable. +# And password in db_pwd's variable. +# +# usage: ynh_mysql_generate_db user name +# | arg: user - Owner of the database +# | arg: name - Name of the database +ynh_mysql_generate_db () { + db_pwd=$(ynh_string_random) # Generate a random password + ynh_mysql_create_db "$2" "$1" "$db_pwd" # Create the database + ynh_app_setting_set $app mysqlpwd $db_pwd # Store the password in the app's config +} + +# Remove a database if it exist and the associated user +# +# usage: ynh_mysql_remove_db user name +# | arg: user - Proprietary of the database +# | arg: name - Name of the database +ynh_mysql_remove_db () { + if mysqlshow -u root -p$(sudo cat $MYSQL_ROOT_PWD_FILE) | grep -q "^| $2"; then # Check if the database exist + echo "Remove database $2" >&2 + ynh_mysql_drop_db $2 # Remove the database + ynh_mysql_drop_user $1 # Remove the associated user to database + else + echo "Database $2 not found" >&2 + fi +} + +# Correct the name given in argument for mariadb +# +# Avoid invalid name for your database +# +# Exemple: dbname=$(ynh_make_valid_dbid $app) +# +# usage: ynh_make_valid_dbid name +# | arg: name - name to correct +# | ret: the corrected name +ynh_make_valid_dbid () { + dbid=${1//[-.]/_} # Mariadb doesn't support - and . in the name of databases. It will be replace by _ + echo $dbid +} + +# Manage a fail of the script +# +# Print a warning to inform that the script was failed +# Execute the ynh_clean_setup function if used in the app script +# +# usage of ynh_clean_setup function +# This function provide a way to clean some residual of installation that not managed by remove script. +# To use it, simply add in your script: +# ynh_clean_setup () { +# instructions... +# } +# This function is optionnal. +# +# Usage: ynh_exit_properly is used only by the helper ynh_abort_if_errors. +# You must not use it directly. +ynh_exit_properly () { + exit_code=$? + if [ "$exit_code" -eq 0 ]; then + exit 0 # Exit without error if the script ended correctly + fi + + trap '' EXIT # Ignore new exit signals + set +eu # Do not exit anymore if a command fail or if a variable is empty + + echo -e "!!\n $app's script has encountered an error. Its execution was cancelled.\n!!" >&2 + + 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. + fi + + ynh_die # Exit with error status +} + +# Exit if an error occurs during the execution of the script. +# +# Stop immediatly the execution if an error occured or if a empty variable is used. +# The execution of the script is derivate to ynh_exit_properly function before exit. +# +# Usage: ynh_abort_if_errors +ynh_abort_if_errors () { + set -eu # Exit if a command fail, and if a variable is used unset. + trap ynh_exit_properly EXIT # Capturing exit signals on shell script +} + +# Define and install dependencies with a equivs control file +# This helper can/should only be called once per app +# +# usage: ynh_install_app_dependencies dep [dep [...]] +# | arg: dep - the package name to install in dependence +ynh_install_app_dependencies () { + dependencies=$@ + manifest_path="../manifest.json" + if [ ! -e "$manifest_path" ]; then + manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place + fi + version=$(sudo python3 -c "import sys, json;print(json.load(open(\"$manifest_path\"))['version'])") # Retrieve the version number in the manifest file. + dep_app=${app//_/-} # Replace all '_' by '-' + + if ynh_package_is_installed "${dep_app}-ynh-deps"; then + echo "A package named ${dep_app}-ynh-deps is already installed" >&2 + else + cat > ./${dep_app}-ynh-deps.control << EOF # Make a control file for equivs-build +Section: misc +Priority: optional +Package: ${dep_app}-ynh-deps +Version: ${version} +Depends: ${dependencies// /, } +Architecture: all +Description: Fake package for ${app} (YunoHost app) dependencies + This meta-package is only responsible of installing its dependencies. +EOF + ynh_package_install_from_equivs ./${dep_app}-ynh-deps.control \ + || ynh_die "Unable to install dependencies" # Install the fake package and its dependencies + ynh_app_setting_set $app apt_dependencies $dependencies + fi +} + +# Remove fake package and its dependencies +# +# Dependencies will removed only if no other package need them. +# +# usage: ynh_remove_app_dependencies +ynh_remove_app_dependencies () { + dep_app=${app//_/-} # Replace all '_' by '-' + ynh_package_autoremove ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used. +} + +# Use logrotate to manage the logfile +# +# usage: ynh_use_logrotate [logfile] +# | arg: logfile - absolute path of logfile +# +# If no argument provided, a standard directory will be use. /var/log/${app} +# You can provide a path with the directory only or with the logfile. +# /parentdir/logdir/ +# /parentdir/logdir/logfile.log +# +# It's possible to use this helper several times, each config will added to same logrotate config file. +ynh_use_logrotate () { + if [ "$#" -gt 0 ]; then + if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile + logfile=$1 # In this case, focus logrotate on the logfile + else + logfile=$1/.log # Else, uses the directory and all logfile into it. + fi + else + logfile="/var/log/${app}/.log" # Without argument, use a defaut directory in /var/log + fi + cat > ./${app}-logrotate << EOF # Build a config file for logrotate +$logfile { + # Rotate if the logfile exceeds 100Mo + size 100M + # Keep 12 old log maximum + rotate 12 + # Compress the logs with gzip + compress + # Compress the log at the next cycle. So keep always 2 non compressed logs + delaycompress + # Copy and truncate the log to allow to continue write on it. Instead of move the log. + copytruncate + # Do not do an error if the log is missing + missingok + # Not rotate if the log is empty + notifempty + # Keep old logs in the same dir + noolddir +} +EOF + sudo mkdir -p $(dirname "$logfile") # Create the log directory, if not exist + cat ${app}-logrotate | sudo tee -a /etc/logrotate.d/$app > /dev/null # Append this config to the others for this app. If a config file already exist +} + +# Remove the app's logrotate config. +# +# usage: ynh_remove_logrotate +ynh_remove_logrotate () { + if [ -e "/etc/logrotate.d/$app" ]; then + sudo rm "/etc/logrotate.d/$app" + fi +} + +# Find a free port and return it +# +# example: port=$(ynh_find_port 8080) +# +# usage: ynh_find_port begin_port +# | arg: begin_port - port to start to search +ynh_find_port () { + port=$1 + test -n "$port" || ynh_die "The argument of ynh_find_port must be a valid port." + while netcat -z 127.0.0.1 $port # Check if the port is free + do + port=$((port+1)) # Else, pass to next port + done + echo $port +} + +# Create a system user +# +# usage: ynh_system_user_create user_name [home_dir] +# | arg: user_name - Name of the system user that will be create +# | arg: home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home +ynh_system_user_create () { + if ! ynh_system_user_exists "$1" # Check if the user exists on the system + then # If the user doesn't exist + if [ $# -ge 2 ]; then # If a home dir is mentioned + user_home_dir="-d $2" + else + user_home_dir="--no-create-home" + fi + sudo useradd $user_home_dir --system --user-group $1 --shell /usr/sbin/nologin || ynh_die "Unable to create $1 system account" + fi +} + +# Delete a system user +# +# usage: ynh_system_user_delete user_name +# | arg: user_name - Name of the system user that will be create +ynh_system_user_delete () { + if ynh_system_user_exists "$1" # Check if the user exists on the system + then + echo "Remove the user $1" >&2 + sudo userdel $1 + else + echo "The user $1 was not found" >&2 + fi +} + +# Curl abstraction to help with POST requests to local pages (such as installation forms) +# +# $domain and $path_url should be defined externally (and correspond to the domain.tld and the /path (of the app?)) +# +# example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2" +# +# usage: ynh_local_curl "page_uri" "key1=value1" "key2=value2" ... +# | arg: page_uri - Path (relative to $path_url) of the page where POST data will be sent +# | arg: key1=value1 - (Optionnal) POST key and corresponding value +# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value +# | arg: ... - (Optionnal) More POST keys and values +ynh_local_curl () { + # Define url of page to curl + full_page_url=https://localhost$path_url$1 + + # Concatenate all other arguments with '&' to prepare POST data + POST_data="" + for arg in "${@:2}" + do + POST_data="${POST_data}${arg}&" + done + # (Remove the last character, which is an unecessary '&') + POST_data=${POST_data::-1} + + # Curl the URL + curl -kL -H "Host: $domain" --resolve $domain:443:127.0.0.1 --data "$POST_data" "$full_page_url" 2>&1 +} + +# Substitute/replace a string by another in a file +# +# usage: ynh_replace_string match_string replace_string target_file +# | arg: match_string - String to be searched and replaced in the file +# | arg: replace_string - String that will replace matches +# | arg: target_file - File in which the string will be replaced. +ynh_replace_string () { + delimit=@ + match_string=${1//${delimit}/"\\${delimit}"} # Escape the delimiter if it's in the string. + replace_string=${2//${delimit}/"\\${delimit}"} + workfile=$3 + + sudo sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$workfile" +} diff --git a/scripts/install b/scripts/install new file mode 100755 index 0000000..0b83a46 --- /dev/null +++ b/scripts/install @@ -0,0 +1,99 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE FAILURE OF THE SCRIPT +#================================================= + +ynh_abort_if_errors # Active trap pour arrêter le script si une erreur est détectée. + +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= + +domain=$YNH_APP_ARG_DOMAIN +is_public=$YNH_APP_ARG_IS_PUBLIC +pvp=$YNH_APP_ARG_PVP +creative=$YNH_APP_ARG_CREATIVE +damage=$YNH_APP_ARG_DAMAGE +app=$YNH_APP_INSTANCE_NAME + +#================================================= +# CHECK THE DEBIAN'S CODENAME +#================================================= + +codename=$(lsb_release -a 2>/dev/null | grep Codename | cut -f 2) +test -z "$codename" && (ynh_die "codename empty") + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# FIND AND OPEN A PORT +#================================================= + +port=$(ynh_find_port 30000) # Cherche un port libre. + +# Ouvre les ports dans le firewall +ALL_QUIET sudo yunohost firewall allow --no-upnp UDP $port +ynh_app_setting_set $app port $port + +# Enregistre les infos dans la config YunoHost +ynh_app_setting_set $app domain ${domain} +ynh_app_setting_set $app is_public ${is_public} +ynh_app_setting_set $app pvp ${pvp} +ynh_app_setting_set $app creative ${creative} +ynh_app_setting_set $app damage ${damage} + +#================================================= +# SPECIFIC SETUP +#================================================= +# INSTALL MINETEST +#================================================= + +# Installation du paquet minetest et ses dépendances +ynh_replace_string "__CODENAME__" "$codename" ../conf/minetest.list +sudo cp -a ../conf/minetest.list /etc/apt/sources.list.d/ +sudo apt-get update +sudo apt-get -qq -t $codename-backports -y install minetest-server + +#================================================= +# ENABLE SERVICE IN ADMIN PANEL +#================================================= + +# Ajoute le service au monitoring de Yunohost. +sudo yunohost service add minetest --log "/var/log/minetest/minetest.log" + +#================================================= +# CONFIGURE MINETEST +#================================================= + +# Modifie la configuration de minetest +ynh_replace_string "__PORT__" "$port" ../conf/minetest.conf +if [ $is_public -eq 1 ] +then + ynh_replace_string "__ANNOUNCE__" "true" ../conf/minetest.conf +else + ynh_replace_string "__ANNOUNCE__" "false" ../conf/minetest.conf +fi +ynh_replace_string "__DOMAIN__" "$domain" ../conf/minetest.conf +ynh_replace_string "__PVP__" "$pvp" ../conf/minetest.conf +ynh_replace_string "__CREATIVE__" "$creative" ../conf/minetest.conf +ynh_replace_string "__DAMAGE__" "$damage" ../conf/minetest.conf +sudo cat ../conf/minetest.conf > /etc/minetest/minetest.conf + +ynh_store_checksum_config "/etc/minetest/minetest.conf" # Enregistre la somme de contrôle du fichier de config + +#================================================= +# RESTART MINETEST'S SERVICE +#================================================= + +# Redémarre minetest pour prendre en compte la nouvelle configuration +sudo systemctl restart minetest-server diff --git a/scripts/remove b/scripts/remove new file mode 100755 index 0000000..8c09cdb --- /dev/null +++ b/scripts/remove @@ -0,0 +1,51 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +port=$(ynh_app_setting_get $app port) + +#================================================= +# STANDARD REMOVE +#================================================= +# DISABLE SERVICE IN ADMIN PANEL +#================================================= + +# Retire le service du monitoring de Yunohost. +if sudo yunohost service status | grep -q minetest # Test l'existence du service dans Yunohost +then + echo "Remove minetest service" + sudo yunohost service remove minetest +fi + +#================================================= +# CLOSE THE PORTS +#================================================= + +# Ferme les ports dans le firewall +ALL_QUIET sudo yunohost firewall disallow UDP $port + +#================================================= +# SPECIFIC REMOVE +#================================================= +# REMOVE MINETEST +#================================================= + +# Suppression du paquet minetest +if [ -e "/usr/lib/minetest/minetestserver" ]; then + echo "Remove minetest package" + sudo apt-get -y purge minetest-server minetest-data +fi +ynh_secure_remove "/etc/apt/sources.list.d/minetest.list"