feat: Add backup.sh
This commit is contained in:
		
							
								
								
									
										66
									
								
								src/baf
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								src/baf
									
									
									
									
									
								
							@@ -1,66 +0,0 @@
 | 
			
		||||
#! /usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# baf -- backup automation micro-framework.
 | 
			
		||||
# Copyright (c) 2022 ge <https://nixhacks.net/>
 | 
			
		||||
#
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
baf_version='0.0.0'
 | 
			
		||||
 | 
			
		||||
BAFLIB="./lib"
 | 
			
		||||
 | 
			
		||||
# Source library
 | 
			
		||||
. ${BAFLIB}/*
 | 
			
		||||
 | 
			
		||||
print_help() {
 | 
			
		||||
    cat <<- EOF
 | 
			
		||||
	Backup files and databases.
 | 
			
		||||
 | 
			
		||||
	Usage: $0 [-hv] <arguments>..
 | 
			
		||||
 | 
			
		||||
	Options:
 | 
			
		||||
	    -h, --help      print this help message and exit.
 | 
			
		||||
	    -v, --version   print version and exit.
 | 
			
		||||
	EOF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Print help if no arguments passed
 | 
			
		||||
[[ "$@" ]] || { print_help; exit 1; }
 | 
			
		||||
 | 
			
		||||
# Transform long options to short ones
 | 
			
		||||
for arg in "$@"; do
 | 
			
		||||
  shift
 | 
			
		||||
  case "$arg" in
 | 
			
		||||
    --help) set -- "$@" "-h";;
 | 
			
		||||
    --version) set -- "$@" "-v";;
 | 
			
		||||
    *) set -- "$@" "$arg";;
 | 
			
		||||
  esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Parse short options
 | 
			
		||||
while getopts ":hvS" opt; do
 | 
			
		||||
    case "$opt" in
 | 
			
		||||
        h) print_help; exit 0;;
 | 
			
		||||
        v) echo "$buf_version"; exit 0;;
 | 
			
		||||
        *) echo "Unknown option $opt" >&2; exit 1;;
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Parse positional arguments
 | 
			
		||||
shift $(($OPTIND - 1))
 | 
			
		||||
while (( "$#" )); do
 | 
			
		||||
    case "$1" in
 | 
			
		||||
        *) posargs+=("$1"); shift;; # Save args
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										136
									
								
								src/bafscript
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										136
									
								
								src/bafscript
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
#! /usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# bafscript -- backup automation micro-framework.
 | 
			
		||||
# Copyright (c) 2022 ge <https://nixhacks.net/>
 | 
			
		||||
#
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
__version='0.0.0'
 | 
			
		||||
__config=
 | 
			
		||||
__log_file='./log.txt'
 | 
			
		||||
__tar_options='-czf'
 | 
			
		||||
__name_date_fmt='_%Y%m%d-%H%M'
 | 
			
		||||
 | 
			
		||||
if [ -n "$BAFLIB" ]; then
 | 
			
		||||
    __library="$BAFLIB"
 | 
			
		||||
else
 | 
			
		||||
    __library='./lib'
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Source library
 | 
			
		||||
for file in "$__library"/*; do
 | 
			
		||||
    . "$file"
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
print_help() {
 | 
			
		||||
    cat <<- EOF
 | 
			
		||||
Backup files and databases.
 | 
			
		||||
 | 
			
		||||
Usage: $0 [-cvlhV] ARGUMENTS..
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
    -c, --config    config file.
 | 
			
		||||
    -v, --verbose   verbose output.
 | 
			
		||||
    -l, --log-file  log file.
 | 
			
		||||
    -h, --help      print this help messagea and exit.
 | 
			
		||||
    -V, --version   print version and exit.
 | 
			
		||||
 | 
			
		||||
Environment:
 | 
			
		||||
    BAFLIB          path to baf library [current: $__library]
 | 
			
		||||
EOF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
# * CLI Arguments Parser                                     #
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
 | 
			
		||||
optval() {
 | 
			
		||||
    # GNU-style CLI options parser.
 | 
			
		||||
    #
 | 
			
		||||
    # Parse --opt VAL and --opt=VAL options.
 | 
			
		||||
    # Requires 2 arguments: $1, $2.
 | 
			
		||||
    # Return variables:
 | 
			
		||||
    #   opt     option name.
 | 
			
		||||
    #   val     option value.
 | 
			
		||||
    #   sft     value for shift.
 | 
			
		||||
 | 
			
		||||
    if [[ "$1" =~ .+=.+ ]]; then
 | 
			
		||||
        opt="${1%%=*}"; val="${1#*=}"; sft=1
 | 
			
		||||
    elif [[ ! "$1" =~ .+=$ ]] && [ "$2" ] && [ "${2:0:1}" != "-" ]; then
 | 
			
		||||
        opt="$1"; val="$2"; sft=2
 | 
			
		||||
    else
 | 
			
		||||
        opt="$1"
 | 
			
		||||
        if [[ "$1" =~ .+=$ ]]; then opt="${1:0: -1}"; fi
 | 
			
		||||
        echo "Error: Missing argument for $opt" >&2; exit 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Print help if no arguments passed
 | 
			
		||||
[[ "$#" == 0 ]] && { print_help; exit 1; }
 | 
			
		||||
 | 
			
		||||
# Split combined short options, e.g. '-abc' to '-a' '-b' '-c'
 | 
			
		||||
for args in "$@"; do
 | 
			
		||||
    shift
 | 
			
		||||
    case "$args" in
 | 
			
		||||
        --*)
 | 
			
		||||
            set -- "$@" "$args";; # save long options
 | 
			
		||||
        -*)
 | 
			
		||||
            args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')"
 | 
			
		||||
            set -- "$@" $args;;
 | 
			
		||||
        *)
 | 
			
		||||
            set -- "$@" "$args";;  # save positional arguments
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Final arguments parser
 | 
			
		||||
while (( "$#" )); do
 | 
			
		||||
    case "$1" in
 | 
			
		||||
        -c|--config|--config=*) optval "$1" "$2"; __config="$val"; shift "$sft";;
 | 
			
		||||
        -v|--verbose) __verbose=1; shift;;
 | 
			
		||||
        -l|--log-file|--log-file=*) optval "$1" "$2"; __log_file="$val"; shift "$sft";;
 | 
			
		||||
        -h|--help) print_help; exit 1;;
 | 
			
		||||
        -V|--version) echo "$__version"; exit 0;;
 | 
			
		||||
        -*) echo "Error: Unknown option: $1" >&2; exit 1;;
 | 
			
		||||
        *)  __args+=("$1"); shift;; # Save positional args
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
# * Do backups                                               #
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
 | 
			
		||||
for script in "${__args[@]}"; do
 | 
			
		||||
    source_script "$script"
 | 
			
		||||
 | 
			
		||||
    # Initialise variables
 | 
			
		||||
    __user_script="$script"
 | 
			
		||||
    backups=()  # Array of created backups, contains full pathes
 | 
			
		||||
 | 
			
		||||
    # Run prepare() before all if set
 | 
			
		||||
    if is_function_set prepare; then
 | 
			
		||||
        prepare
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Run user defined backup() if set or builtin_backup()
 | 
			
		||||
    if is_function_set backup; then
 | 
			
		||||
        backup
 | 
			
		||||
    else
 | 
			
		||||
        builtin_backup
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # Run post backup function if set
 | 
			
		||||
    if is_function_set finalise; then
 | 
			
		||||
        finalise
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
							
								
								
									
										251
									
								
								src/lib/backup.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/lib/backup.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
#! /usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# backup.sh - functions for backup processing.
 | 
			
		||||
# Copyright (c) 2022 ge <https://nixhacks.net/>
 | 
			
		||||
#
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
process_source() {
 | 
			
		||||
    # Run handler function for source URI by scheme.
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: process_source URI
 | 
			
		||||
 | 
			
		||||
    local uri
 | 
			
		||||
    local scheme
 | 
			
		||||
    local handler
 | 
			
		||||
 | 
			
		||||
    uri="$1"
 | 
			
		||||
    scheme="${uri%%:*}"
 | 
			
		||||
 | 
			
		||||
    case "$scheme" in
 | 
			
		||||
        file)   handler='backup_files';;
 | 
			
		||||
        mysql)  handler='backup_mysql';;
 | 
			
		||||
        postgres) handler='backup_postgres';;
 | 
			
		||||
        sqlite) handler='backup_sqlite';;
 | 
			
		||||
        *) echo "Error: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    # Run handler function
 | 
			
		||||
    "$handler" "$uri"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
process_target() {
 | 
			
		||||
    # Run handler function for target URI by scheme.
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: process_target URI
 | 
			
		||||
 | 
			
		||||
    local uri
 | 
			
		||||
    local scheme
 | 
			
		||||
    local handler
 | 
			
		||||
 | 
			
		||||
    uri="$1"
 | 
			
		||||
    scheme="${uri%%:*}"
 | 
			
		||||
 | 
			
		||||
    case "$scheme" in
 | 
			
		||||
        file)   handler='transfer_files';;
 | 
			
		||||
        ftp)    handler='transfer_ftp';;
 | 
			
		||||
        sftp)   handler='transfer_sftp';;
 | 
			
		||||
        rsync)  handler='transfer_rsync';;
 | 
			
		||||
        s3)     handler='transfer_s3';;
 | 
			
		||||
        sj)     handler='transfer_sj';;
 | 
			
		||||
        swift)  handler='transfer_swift';;
 | 
			
		||||
        dav)    handler='transfer_dav';;
 | 
			
		||||
        davs)   handler='transfer_davs';;
 | 
			
		||||
        *) echo "Error: Unsupported URI scheme: $scheme" >&2; exit 1;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    # Run handler function
 | 
			
		||||
    "$handler" "$uri"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
builtin_backup() {
 | 
			
		||||
    # Backup function.
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: builtin_backup
 | 
			
		||||
 | 
			
		||||
    for source in "${sources[@]}"; do
 | 
			
		||||
        process_source "$source"
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
    for target in "${targets[@]}"; do
 | 
			
		||||
        process_target "$target"
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
# * Backup functions                                         #
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
 | 
			
		||||
backup_files() {
 | 
			
		||||
    # Backup local files with tar(1). Handle 'file' URI scheme.
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: backup_files URI
 | 
			
		||||
 | 
			
		||||
    local uri
 | 
			
		||||
    local src_path
 | 
			
		||||
    local dst_path
 | 
			
		||||
    local archive
 | 
			
		||||
    local file_ext
 | 
			
		||||
 | 
			
		||||
    uri="$1"
 | 
			
		||||
    dst_path="$__main_target_path"
 | 
			
		||||
 | 
			
		||||
    parse_uri "$uri"
 | 
			
		||||
 | 
			
		||||
    if [ -f "$path" ] || [ -d "$path" ]; then
 | 
			
		||||
        src_path="$path"
 | 
			
		||||
    else
 | 
			
		||||
        echo "Error: Path '$path' from URI '$uri' does not exists" >&2
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    is_installed tar # Exit if tar is not installed
 | 
			
		||||
 | 
			
		||||
    # Overwrire __tar_options
 | 
			
		||||
    if [ -n "$tar_options" ]; then
 | 
			
		||||
        __tar_options="$tar_options"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # TODO выбор сжатия, можно в переменной __tar_options заменять букву z на
 | 
			
		||||
    # другую для соответствующего сжатия
 | 
			
		||||
    file_ext=.tar.gz
 | 
			
		||||
 | 
			
		||||
    archive="${dst_path}/$(gen_backup_name "$file_ext")"
 | 
			
		||||
 | 
			
		||||
    tar "$__tar_options" "$archive" "$src_path" |& log -p
 | 
			
		||||
 | 
			
		||||
    # Append path to 'backups' array
 | 
			
		||||
    backups+=("$archive")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
backup_mysql() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
backup_postgres() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
backup_sqlite() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
# * Functions for targets processing                         #
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
 | 
			
		||||
transfer_files() {
 | 
			
		||||
    # Transfer files to another location from __main_target_path using cp(1)
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: transfer_files URI
 | 
			
		||||
 | 
			
		||||
    local uri
 | 
			
		||||
    local dst_path
 | 
			
		||||
 | 
			
		||||
    uri="$1"
 | 
			
		||||
 | 
			
		||||
    if [[ "$uri" == "$__main_target" ]]; then
 | 
			
		||||
        : # Do nothing. Source and destination is the same
 | 
			
		||||
    else
 | 
			
		||||
        # Copy backups to another destination
 | 
			
		||||
        parse_uri "$uri"
 | 
			
		||||
 | 
			
		||||
        if [ -f "$path" ] || [ -d "$path" ]; then
 | 
			
		||||
            dst_path="$path"
 | 
			
		||||
        else
 | 
			
		||||
            echo "Error: Path '$path' from URI '$uri' does not exists" >&2
 | 
			
		||||
            exit 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # Copy files preserving metadata
 | 
			
		||||
        for backup in "${backups[@]}"; do
 | 
			
		||||
            cp --archive "$backup" "$dst_path"
 | 
			
		||||
        done
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_ftp() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_sftp() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_rsync() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_s3() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_sj() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_swift() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_dav() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
transfer_davs() {
 | 
			
		||||
    echo Not implemented >&2; exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
# * Helper functions                                         #
 | 
			
		||||
# ---------------------------------------------------------- #
 | 
			
		||||
 | 
			
		||||
is_installed() {
 | 
			
		||||
    # Check if the program is installed.
 | 
			
		||||
    # See good answer: https://stackoverflow.com/a/677212
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: is_installed COMMAND
 | 
			
		||||
 | 
			
		||||
    local cmd
 | 
			
		||||
 | 
			
		||||
    cmd="$1"
 | 
			
		||||
 | 
			
		||||
    if ! command -v "$cmd" >/dev/null 2>&1; then
 | 
			
		||||
        echo "Error: Command $cmd not found." \
 | 
			
		||||
            "Please install $cmd or check your PATH if it's actually installed." >&2
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gen_backup_name() {
 | 
			
		||||
    # Generate backup file name. Return (echo) string.
 | 
			
		||||
    #
 | 
			
		||||
    # Usage: gen_backup_name NAME_EXT
 | 
			
		||||
 | 
			
		||||
    local prefix
 | 
			
		||||
    local name
 | 
			
		||||
    local date_fmt
 | 
			
		||||
    local name_ext
 | 
			
		||||
 | 
			
		||||
    [ -n "$name_prefix" ] || { prefix="${__user_script}_"; }
 | 
			
		||||
    name="$(basename $path)" # 'path' is variable parsed from URI
 | 
			
		||||
    name_ext="$1"
 | 
			
		||||
 | 
			
		||||
    # Overwrite __name_date_fmt
 | 
			
		||||
    if [ -n "$name_date_fmt" ]; then
 | 
			
		||||
        __name_date_fmt="$name_date_fmt"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    date +"${prefix}${name}${__name_date_fmt}${name_ext}"
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user