-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add a real shell argument parser, add --instance arg, documentation, refactoring, cleanup
- Loading branch information
Showing
7 changed files
with
388 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ minecraftd-backup.service | |
minecraftd-backup.timer | ||
[email protected] | ||
[email protected] | ||
[email protected] | ||
minecraftd.conf | ||
minecraftd.service | ||
minecraftd.sh | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
SHELL = /bin/sh | ||
INSTALL = install | ||
INSTALL_PROGRAM = $(INSTALL) -m755 | ||
INSTALL_DIR = $(INSTALL) -d -m755 | ||
INSTALL_DATA = $(INSTALL) -m644 | ||
confdir = /etc/conf.d | ||
prefix = /usr | ||
|
@@ -20,10 +21,13 @@ CONFIG_PATH = /etc/conf.d/$(GAME) | |
SYSCONFDIR = /etc | ||
INSTANCE_CONFIG_DIR = $(SYSCONFDIR)/$(GAME) | ||
BACKUP_DEST = $(SERVER_ROOT)/backup | ||
LIBRARY_PATH = $(libdir)/$(GAME) | ||
BACKUP_PATHS = world | ||
BACKUP_FLAGS = -z | ||
KEEP_BACKUPS = 10 | ||
GAME_USER = $(GAME) | ||
SERVER_MEMORY_INITIAL = 512 | ||
SERVER_MEMORY_MAXIMUM = 1024 | ||
MAIN_EXECUTABLE = minecraft_server.jar | ||
ifeq ($(MAIN_EXECUTABLE),$(MAIN_EXECUTABLE:/%=)) | ||
MAIN_EXECUTABLE_ABSOLUTE = $(SERVER_ROOT)/$(MAIN_EXECUTABLE) | ||
|
@@ -32,14 +36,14 @@ MAIN_EXECUTABLE_ABSOLUTE = $(MAIN_EXECUTABLE) | |
endif | ||
TMUX_SOCKET_DIR = /run/$(GAME)/tmux | ||
SESSION_NAME = $(GAME) | ||
SERVER_START_CMD = java -Xms512M -Xmx1024M -jar ./$${MAIN_EXECUTABLE} nogui | ||
SERVER_START_CMD = java -Xms@SERVER_MEMORY_INITIAL@M -Xmx@SERVER_MEMORY_MAXIMUM@M -jar @MAIN_EXECUTABLE@ nogui | ||
SERVER_START_SUCCESS = done | ||
IDLE_SERVER = false | ||
IDLE_SESSION_NAME = idle_server_$${SESSION_NAME} | ||
IDLE_SESSION_NAME = idle_server_@SESSION_NAME@ | ||
GAME_PORT = 25565 | ||
CHECK_PLAYER_TIME = 30 | ||
IDLE_IF_TIME = 1200 | ||
GAME_COMMAND_DUMP = /tmp/$${INAME}_$${SESSION_NAME}_command_dump.txt | ||
GAME_COMMAND_DUMP = /tmp/@INAME@_@SESSION_NAME@_command_dump.txt | ||
|
||
.MAIN = all | ||
|
||
|
@@ -50,6 +54,7 @@ define replace_all | |
-e 's#@GAME@#$(GAME)#g' \ | ||
-e 's#@SERVER_ROOT@#$(SERVER_ROOT)#g' \ | ||
-e 's#@CONFIG_PATH@#$(CONFIG_PATH)#g' \ | ||
-e 's#@LIBRARY_PATH@#$(LIBRARY_PATH)#g' \ | ||
-e 's#@SYSCONFDIR@#$(SYSCONFDIR)#g' \ | ||
-e 's#@INSTANCE_CONFIG_DIR@#$(INSTANCE_CONFIG_DIR)#g' \ | ||
-e 's#@BACKUP_DEST@#$(BACKUP_DEST)#g' \ | ||
|
@@ -59,6 +64,8 @@ define replace_all | |
-e 's#@GAME_USER@#$(GAME_USER)#g' \ | ||
-e 's#@MAIN_EXECUTABLE@#$(MAIN_EXECUTABLE)#g' \ | ||
-e 's#@MAIN_EXECUTABLE_ABSOLUTE@#$(MAIN_EXECUTABLE_ABSOLUTE)#g' \ | ||
-e 's#@SERVER_MEMORY_INITIAL@#$(SERVER_MEMORY_INITIAL)#g' \ | ||
-e 's#@SERVER_MEMORY_MAXIMUM@#$(SERVER_MEMORY_MAXIMUM)#g' \ | ||
-e 's#@TMUX_SOCKET_DIR@#$(TMUX_SOCKET_DIR)#g' \ | ||
-e 's#@SESSION_NAME@#$(SESSION_NAME)#g' \ | ||
-e 's#@SERVER_START_CMD@#$(SERVER_START_CMD)#g' \ | ||
|
@@ -102,15 +109,17 @@ maintainer-clean: clean | |
|
||
install: | ||
$(INSTALL_PROGRAM) -D minecraftd.sh "$(DESTDIR)$(bindir)/$(INAME)" | ||
$(INSTALL_DATA) -D minecraftd.conf "$(DESTDIR)$(confdir)/$(GAME)" | ||
$(INSTALL_DATA) -D minecraftd.service "$(DESTDIR)$(libdir)/systemd/system/$(INAME).service" | ||
$(INSTALL_DATA) -D minecraftd-backup.service "$(DESTDIR)$(libdir)/systemd/system/$(INAME)-backup.service" | ||
$(INSTALL_DATA) -D minecraftd-backup.timer "$(DESTDIR)$(libdir)/systemd/system/$(INAME)-backup.timer" | ||
$(INSTALL_DIR) "$(DESTDIR)$(LIBRARY_PATH)" | ||
$(INSTALL_DATA) -D argparse.sh "$(DESTDIR)$(LIBRARY_PATH)/argparse.sh" | ||
$(INSTALL_DATA) -D minecraftd.conf "$(DESTDIR)$(confdir)/$(GAME)" | ||
$(INSTALL_DATA) -D minecraftd.service "$(DESTDIR)$(libdir)/systemd/system/$(INAME).service" | ||
$(INSTALL_DATA) -D minecraftd-backup.service "$(DESTDIR)$(libdir)/systemd/system/$(INAME)-backup.service" | ||
$(INSTALL_DATA) -D minecraftd-backup.timer "$(DESTDIR)$(libdir)/systemd/system/$(INAME)-backup.timer" | ||
$(INSTALL_DATA) -D [email protected] "$(DESTDIR)$(libdir)/systemd/system/$(INAME)@.service" | ||
$(INSTALL_DATA) -D [email protected] "$(DESTDIR)$(libdir)/systemd/system/$(INAME)[email protected]" | ||
$(INSTALL_DATA) -D [email protected] "$(DESTDIR)$(libdir)/systemd/system/$(INAME)[email protected]" | ||
$(INSTALL_DATA) -D minecraftd.sysusers "$(DESTDIR)$(libdir)/sysusers.d/$(INAME).conf" | ||
$(INSTALL_DATA) -D minecraftd.tmpfiles "$(DESTDIR)$(libdir)/tmpfiles.d/$(INAME).conf" | ||
$(INSTALL_DATA) -D minecraftd.sysusers "$(DESTDIR)$(libdir)/sysusers.d/$(INAME).conf" | ||
$(INSTALL_DATA) -D minecraftd.tmpfiles "$(DESTDIR)$(libdir)/tmpfiles.d/$(INAME).conf" | ||
|
||
uninstall: | ||
rm -f "$(bindir)/$(INAME)" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
#!/bin/bash | ||
|
||
# shell script library to parse and validate command line arguments, and generate the --help text. | ||
|
||
set -u | ||
|
||
re_subcmd_vn='^[a-z0-9]+:[A-Za-z0-9_]+$' | ||
COMMAND= | ||
|
||
declare -A args args_help subcmds | ||
|
||
add_arg() { | ||
local short="$1" | ||
local long="$2" | ||
local varname="$3" | ||
local help="$4" | ||
local required="${5:-false}" | ||
[ -v 6 ] && local default="$6" | ||
if [[ "$varname" =~ $re_subcmd_vn ]]; then | ||
local subc _vn | ||
IFS=":" read subc _vn <<< "$varname" | ||
[[ -n "${subcmds[$subc]}" ]] | ||
fi | ||
args[$varname]="$short $long $required" | ||
args_help[$varname]="$help" | ||
# init the global | ||
[[ -v default ]] && declare -g ${varname#*:}="${default}" | ||
} | ||
|
||
add_subcommand() { | ||
local subc="$1" | ||
local help="$2" | ||
|
||
subcmds[$subc]="$help" | ||
} | ||
|
||
usage() { | ||
# help function. generates usage instructions | ||
local short long required help | ||
local n_subcmds=${#subcmds[@]} | ||
local ofd=1 | ||
[[ -v 1 ]] && ofd=2 | ||
local cols=80 | ||
[[ -t $ofd ]] && cols=$(tput cols) | ||
( | ||
if [[ -v 1 ]]; then | ||
echo "ERROR: $1" | ||
echo "" | ||
fi | ||
if [[ -v DESCRIPTION ]]; then | ||
echo -e "$DESCRIPTION" | ||
echo "" | ||
fi | ||
if [[ $n_subcmds < 1 ]]; then | ||
echo "Usage: $0 [options]" | ||
echo "" | ||
echo "Valid options are:" | ||
else | ||
echo "Usage: $0 [global options] COMMAND [command-specific options]" | ||
echo "" | ||
echo "Global options:" | ||
fi | ||
for varname in ${!args[@]}; do | ||
[[ $varname =~ $re_subcmd_vn ]] && continue | ||
IFS=" " read short long required <<< "${args[$varname]}" | ||
help="${args_help[$varname]}" | ||
printf " -%s, --%-16s %s (required: %s)\n" "$short" "$long" "$help" "$required" | ||
done | ||
|
||
if [[ $n_subcmds > 0 ]]; then | ||
echo "" | ||
echo "Valid commands:" | ||
for subcmd in ${!subcmds[@]}; do | ||
printf " %-12s %s\n" "$subcmd" "${subcmds[$subcmd]}" | ||
done | ||
|
||
for subcmd in ${!subcmds[@]}; do | ||
echo "" | ||
echo "Options for command \"$subcmd\":" | ||
local n=0 | ||
for varname in ${!args[@]}; do | ||
[[ "${varname%:*}" == "$subcmd" ]] || continue | ||
((n++)) | ||
IFS=" " read short long required <<< "${args[$varname]}" | ||
help="${args_help[$varname]}" | ||
printf " -%s, --%-16s %s (required: %s)\n" "$short" "$long" "$help" "$required" | ||
done | ||
[[ $n == 0 ]] && echo " (None)" | ||
done | ||
echo "" | ||
|
||
[[ -v COPYRIGHT ]] && echo -e "$COPYRIGHT" | ||
fi | ||
) | fold -w "$cols" -s >&$ofd | ||
exit 1 | ||
} | ||
|
||
parse_args() { | ||
local short long required longprefix found | ||
local n_subcmds=${#subcmds[@]} | ||
declare -a bareargs reqargs | ||
while [[ -v 1 ]]; do | ||
case "$1" in | ||
--help|-h) | ||
usage ;; | ||
-*) | ||
# parse as named option | ||
found=false | ||
for varname in ${!args[@]}; do | ||
IFS=" " read short long required <<< "${args[$varname]}" | ||
if [[ $varname =~ $re_subcmd_vn ]]; then | ||
# subcommand option | ||
local vsubc _vn | ||
IFS=":" read vsubc _vn <<< "$varname" | ||
[[ "$vsubc" = "$COMMAND" ]] || continue | ||
varname=$_vn | ||
fi | ||
longprefix="--$long=" | ||
case "$1" in | ||
-$short|--$long) | ||
[[ -v 2 ]] || usage "value for argument $1 may not be omitted" | ||
declare -g $varname="$2" | ||
found=true | ||
shift | ||
;; | ||
$longprefix*) | ||
found=true | ||
declare -g $varname=${1:${#longprefix}} | ||
;; | ||
esac | ||
done | ||
[[ "$found" == "true" ]] || usage "Unknown option: $1" | ||
;; | ||
*) | ||
if [[ $n_subcmds > 0 && $COMMAND == "" ]]; then | ||
COMMAND="$1" | ||
[[ -v subcmds[$COMMAND] ]] || usage "Undefined command: $COMMAND" | ||
else | ||
bareargs+=("$1") | ||
fi | ||
;; | ||
esac | ||
shift | ||
done | ||
|
||
[[ $n_subcmds > 0 && $COMMAND == "" ]] && usage "No command was given." | ||
|
||
# build list of missing required args | ||
for varname in ${!args[@]}; do | ||
IFS=" " read short long required <<< "${args[$varname]}" | ||
[[ "$required" == "true" ]] || continue | ||
if [[ $varname =~ $re_subcmd_vn ]]; then | ||
# subcommand option | ||
local vsubc _vn | ||
IFS=":" read vsubc _vn <<< "$varname" | ||
[[ "$vsubc" = "$COMMAND" ]] || continue | ||
[[ -v $_vn ]] && continue | ||
reqargs+=("$varname") | ||
else | ||
[[ -v $varname ]] && continue | ||
reqargs+=("$varname") | ||
fi | ||
done | ||
# process bareword args | ||
while [[ -v bareargs[0] && -v reqargs[0] ]]; do | ||
declare -g ${reqargs[0]#*:}=${bareargs[0]} | ||
bareargs=("${bareargs[@]:1}") | ||
reqargs=("${reqargs[@]:1}") | ||
done | ||
|
||
# if there's any bareword arguments left, we are out of ideas for what to do with them, so fail. | ||
[[ -v bareargs[0] ]] && usage "Unknown argument: ${bareargs[0]}" | ||
|
||
# enforce required args | ||
for varname in ${!args[@]}; do | ||
IFS=" " read short long required <<< "${args[$varname]}" | ||
[[ "$required" == "true" ]] || continue | ||
if [[ $varname =~ $re_subcmd_vn ]]; then | ||
# subcommand arg | ||
local vsubc _vn | ||
IFS=":" read vsubc _vn <<< "$varname" | ||
[[ "$vsubc" == "$COMMAND" ]] || continue | ||
[[ ! -v $_vn ]] && usage "Option is required for command $vsubc but not set: $long" | ||
else | ||
# global arg | ||
[[ ! -v $varname ]] && usage "Required option or positional argument not set: $long" | ||
fi | ||
done | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[Unit] | ||
Description=Create server directories for @GAME@ %i instance | ||
After=local-fs.target network.target multi-user.target | ||
|
||
[Service] | ||
Type=oneshot | ||
RemainAfterExit=no | ||
# create the "servers" directory followed by the instance directory | ||
ExecStart=/usr/bin/@INAME@ -i %i init | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
Oops, something went wrong.