Pass shellcheck

This commit is contained in:
Nicolas Chan 2021-03-03 22:59:31 -08:00
parent 71311e2321
commit 80abd684ba
3 changed files with 61 additions and 43 deletions

View file

@ -26,6 +26,13 @@ WINDOW_MANAGER="screen" # Choices: screen, tmux
DATE_FORMAT="%F_%H-%M-%S"
TIMESTAMP=$(date +$DATE_FORMAT)
log-fatal () {
echo -e "\033[0;31mFATAL:\033[0m $*"
}
log-warning () {
echo -e "\033[0;33mWARNING:\033[0m $*"
}
while getopts 'a:cd:e:f:hi:l:m:o:p:qs:vw:' FLAG; do
case $FLAG in
a) COMPRESSION_ALGORITHM=$OPTARG ;;
@ -61,20 +68,14 @@ while getopts 'a:cd:e:f:hi:l:m:o:p:qs:vw:' FLAG; do
s) SCREEN_NAME=$OPTARG ;;
v) DEBUG=true ;;
w) WINDOW_MANAGER=$OPTARG ;;
*) log-fatal "Invalid option -$FLAG"; exit 1 ;;
esac
done
log-fatal () {
echo -e "\033[0;31mFATAL:\033[0m $*"
}
log-warning () {
echo -e "\033[0;33mWARNING:\033[0m $*"
}
rcon-command () {
HOST="$(echo $1 | cut -d: -f1)"
PORT="$(echo $1 | cut -d: -f2)"
PASSWORD="$(echo $1 | cut -d: -f3-)"
HOST="$(echo "$1" | cut -d: -f1)"
PORT="$(echo "$1" | cut -d: -f2)"
PASSWORD="$(echo "$1" | cut -d: -f3-)"
COMMAND="$2"
reverse-hex-endian () {
@ -255,50 +256,54 @@ message-players "Starting backup..." "$ARCHIVE_FILE_NAME"
# Parse file timestamp to one readable by "date"
parse-file-timestamp () {
local DATE_STRING=$(echo $1 | awk -F_ '{gsub(/-/,":",$2); print $1" "$2}')
echo $DATE_STRING
local DATE_STRING
DATE_STRING="$(echo "$1" | awk -F_ '{gsub(/-/,":",$2); print $1" "$2}')"
echo "$DATE_STRING"
}
# Delete a backup
delete-backup () {
local BACKUP=$1
rm $BACKUP_DIRECTORY/$BACKUP
rm "$BACKUP_DIRECTORY"/"$BACKUP"
message-players "Deleted old backup" "$BACKUP"
}
# Sequential delete method
delete-sequentially () {
local BACKUPS=($(ls $BACKUP_DIRECTORY))
local BACKUPS=("$BACKUP_DIRECTORY"/*)
while [[ $MAX_BACKUPS -ge 0 && ${#BACKUPS[@]} -gt $MAX_BACKUPS ]]; do
delete-backup ${BACKUPS[0]}
BACKUPS=($(ls $BACKUP_DIRECTORY))
delete-backup "$(basename "${BACKUPS[0]}")"
BACKUPS=("$BACKUP_DIRECTORY"/*)
done
}
# Functions to sort backups into correct categories based on timestamps
is-hourly-backup () {
local TIMESTAMP=$*
local MINUTE=$(date -d "$TIMESTAMP" +%M)
return $MINUTE
local MINUTE
MINUTE=$(date -d "$TIMESTAMP" +%M)
return "$MINUTE"
}
is-daily-backup () {
local TIMESTAMP=$*
local HOUR=$(date -d "$TIMESTAMP" +%H)
return $HOUR
local HOUR
HOUR=$(date -d "$TIMESTAMP" +%H)
return "$HOUR"
}
is-weekly-backup () {
local TIMESTAMP=$*
local DAY=$(date -d "$TIMESTAMP" +%u)
return $((DAY - 1))
local DAY
DAY=$(date -d "$TIMESTAMP" +%u)
return "$((DAY - 1))"
}
# Helper function to sum an array
array-sum () {
SUM=0
for NUMBER in $*; do
for NUMBER in "$@"; do
(( SUM += NUMBER ))
done
echo $SUM
echo "$SUM"
}
# Thinning delete method
@ -310,7 +315,7 @@ delete-thinning () {
local BLOCK_FUNCTIONS=("is-hourly-backup" "is-daily-backup" "is-weekly-backup")
# Warn if $MAX_BACKUPS does not have enough room for all the blocks
TOTAL_BLOCK_SIZE=$(array-sum ${BLOCK_SIZES[@]})
TOTAL_BLOCK_SIZE=$(array-sum "${BLOCK_SIZES[@]}")
if [[ $MAX_BACKUPS != -1 ]] && [[ $TOTAL_BLOCK_SIZE -gt $MAX_BACKUPS ]]; then
if ! $SUPPRESS_WARNINGS; then
log-warning "MAX_BACKUPS ($MAX_BACKUPS) is smaller than TOTAL_BLOCK_SIZE ($TOTAL_BLOCK_SIZE)"
@ -318,19 +323,21 @@ delete-thinning () {
fi
local CURRENT_INDEX=0
local BACKUPS=($(ls -r $BACKUP_DIRECTORY)) # List newest first
local BACKUPS=("$BACKUP_DIRECTORY"/*) # List newest first
for BLOCK_INDEX in ${!BLOCK_SIZES[@]}; do
for BLOCK_INDEX in "${!BLOCK_SIZES[@]}"; do
local BLOCK_SIZE=${BLOCK_SIZES[BLOCK_INDEX]}
local BLOCK_FUNCTION=${BLOCK_FUNCTIONS[BLOCK_INDEX]}
local OLDEST_BACKUP_IN_BLOCK_INDEX=$((BLOCK_SIZE + CURRENT_INDEX)) # Not an off-by-one error because a new backup was already saved
local OLDEST_BACKUP_IN_BLOCK=${BACKUPS[OLDEST_BACKUP_IN_BLOCK_INDEX]}
local OLDEST_BACKUP_IN_BLOCK
OLDEST_BACKUP_IN_BLOCK="$(basename "${BACKUPS[OLDEST_BACKUP_IN_BLOCK_INDEX]}")"
if [[ $OLDEST_BACKUP_IN_BLOCK == "" ]]; then
if [[ "$OLDEST_BACKUP_IN_BLOCK" == "" ]]; then
break
fi
local OLDEST_BACKUP_TIMESTAMP=$(parse-file-timestamp ${OLDEST_BACKUP_IN_BLOCK:0:19})
local OLDEST_BACKUP_TIMESTAMP
OLDEST_BACKUP_TIMESTAMP=$(parse-file-timestamp "${OLDEST_BACKUP_IN_BLOCK:0:19}")
local BLOCK_COMMAND="$BLOCK_FUNCTION $OLDEST_BACKUP_TIMESTAMP"
if $BLOCK_COMMAND; then
@ -340,7 +347,7 @@ delete-thinning () {
fi
else
# Oldest backup in this block does not satisfy the condition for placement in next block
delete-backup $OLDEST_BACKUP_IN_BLOCK
delete-backup "$OLDEST_BACKUP_IN_BLOCK"
break
fi
@ -351,7 +358,7 @@ delete-thinning () {
}
# Ensure directory exists
mkdir -p "$(dirname $ARCHIVE_PATH)"
mkdir -p "$(dirname "$ARCHIVE_PATH")"
# Disable world autosaving
execute-command "save-off"
@ -360,10 +367,10 @@ execute-command "save-off"
START_TIME=$(date +"%s")
case $COMPRESSION_ALGORITHM in
# No compression
"") tar -cf $ARCHIVE_PATH -C $SERVER_WORLD .
"") tar -cf "$ARCHIVE_PATH" -C "$SERVER_WORLD" .
;;
# With compression
*) tar -cf - -C $SERVER_WORLD . | $COMPRESSION_ALGORITHM -cv -$COMPRESSION_LEVEL - > $ARCHIVE_PATH 2>> /dev/null
*) tar -cf - -C "$SERVER_WORLD" . | $COMPRESSION_ALGORITHM -cv -"$COMPRESSION_LEVEL" - > "$ARCHIVE_PATH" 2>> /dev/null
;;
esac
sync
@ -386,15 +393,15 @@ delete-old-backups () {
}
# Notify players of completion
WORLD_SIZE_BYTES=$(du -b --max-depth=0 $SERVER_WORLD | awk '{print $1}')
ARCHIVE_SIZE_BYTES=$(du -b $ARCHIVE_PATH | awk '{print $1}')
ARCHIVE_SIZE=$(du -h $ARCHIVE_PATH | awk '{print $1}')
BACKUP_DIRECTORY_SIZE=$(du -h --max-depth=0 $BACKUP_DIRECTORY | awk '{print $1}')
WORLD_SIZE_BYTES=$(du -b --max-depth=0 "$SERVER_WORLD" | awk '{print $1}')
ARCHIVE_SIZE_BYTES=$(du -b "$ARCHIVE_PATH" | awk '{print $1}')
ARCHIVE_SIZE=$(du -h "$ARCHIVE_PATH" | awk '{print $1}')
BACKUP_DIRECTORY_SIZE=$(du -h --max-depth=0 "$BACKUP_DIRECTORY" | awk '{print $1}')
TIME_DELTA=$((END_TIME - START_TIME))
# Check that archive size is not null and at least 200 Bytes
if [[ "$WORLD_SIZE_BYTES" -gt 0 && "$ARCHIVE_SIZE" != "" && "$ARCHIVE_SIZE_BYTES" -gt 200 ]]; then
COMPRESSION_PERCENT=$(($ARCHIVE_SIZE_BYTES * 100 / $WORLD_SIZE_BYTES))
COMPRESSION_PERCENT=$((ARCHIVE_SIZE_BYTES * 100 / WORLD_SIZE_BYTES))
message-players-success "Backup complete!" "$TIME_DELTA s, $ARCHIVE_SIZE/$BACKUP_DIRECTORY_SIZE, $COMPRESSION_PERCENT%"
delete-old-backups
else

View file

@ -1,9 +1,9 @@
#!/usr/bin/env bash
rcon-command () {
HOST="$(echo $1 | cut -d: -f1)"
PORT="$(echo $1 | cut -d: -f2)"
PASSWORD="$(echo $1 | cut -d: -f3-)"
HOST="$(echo "$1" | cut -d: -f1)"
PORT="$(echo "$1" | cut -d: -f2)"
PASSWORD="$(echo "$1" | cut -d: -f3-)"
COMMAND="$2"
reverse-hex-endian () {

View file

@ -21,7 +21,10 @@ setUp () {
tmux send-keys -t "$SCREEN_TMP" "cat > $TEST_TMP/tmux-output" ENTER
python test/mock_rcon.py "$RCON_PORT" "$RCON_PASSWORD" > "$TEST_TMP/rcon-output" &
echo "$!" > "$TEST_TMP/rcon-pid"
sleep 1
while ! [[ (-f "$TEST_TMP/screen-output") && (-f "$TEST_TMP/tmux-output") && (-f "$TEST_TMP/rcon-output") ]]; do
sleep 0.1
done
}
tearDown () {
@ -106,6 +109,13 @@ test-missing-options-suppress-warnings () {
assertNotContains "$OUTPUT" "Minecraft screen/tmux/rcon location not specified (use -s)"
}
test-invalid-options () {
OUTPUT="$(./backup.sh -z 2>&1)"
EXIT_CODE="$?"
assertEquals 1 "$EXIT_CODE"
assertContains "$OUTPUT" "Invalid option"
}
test-empty-world-warning () {
mkdir -p "$TEST_TMP/server/empty-world"
OUTPUT="$(./backup.sh -v -i "$TEST_TMP/server/empty-world" -o "$TEST_TMP/backups" -s "$SCREEN_TMP" -f "$TIMESTAMP" 2>&1)"
@ -158,6 +168,7 @@ test-sequential-delete () {
TIMESTAMP="$(date +%F_%H-%M-%S --date="2021-01-01 +$i hour")"
check-backup "$TIMESTAMP.tar.gz"
done
assertEquals 10 "$(find "$TEST_TMP/backups" -type f | wc -l)"
}
test-thinning-delete () {