Compare commits

...

15 Commits

Author SHA1 Message Date
Asif Bacchus c73a3b8531 style: cleanup formatting, spelling
- use project-custom dictionary
- cleanup spelling mistakes
- rename functions to conform with camelCase for spellcheck
- reformat file: spacing, indentation
2021-05-15 09:15:57 -06:00
Asif Bacchus 8b201ca047 feature(add option for separate keyfile): 2021-05-15 09:05:04 -06:00
Asif Bacchus a86f13a1e5 perf: run help automatically as needed 2021-05-15 08:58:39 -06:00
Asif Bacchus 7b87c246c3 struct: update mod time, remove vscode dir 2021-05-15 08:58:13 -06:00
Asif Bacchus 29ab2c11a3 derive restorePath abs path
Fixes the touch.test removal error and is more robust in commands.
2020-03-27 02:59:17 -06:00
Asif Bacchus 37bd4e69c6 Merge branch 'master' of https://git.asifbacchus.app/asif/borgScripts 2020-03-27 00:36:41 -06:00
Asif Bacchus d000369b7d add file/pattern search to archive contents list 2020-03-27 00:36:35 -06:00
Asif Bacchus d29dec95e2 only create restorePath if operation is 'restore' 2020-03-26 08:06:01 -06:00
Asif Bacchus f18de4f411 update readme 2020-03-26 06:55:46 -06:00
Asif Bacchus d6eae39603 remove unused 'yellow' var 2020-03-26 06:50:07 -06:00
Asif Bacchus 8331ff712c add header comment and disclaimer 2020-03-26 06:49:08 -06:00
Asif Bacchus 7cc69a616a create restorePath if it does not exist 2020-03-26 06:44:38 -06:00
Asif Bacchus cfd7d6ede0 remove write-test file in restorePath 2020-03-26 06:43:38 -06:00
Asif Bacchus 4dc77ca3ae update error code list 2020-03-26 06:30:56 -06:00
Asif Bacchus 71b77857a6 add in-script help 2020-03-26 06:27:34 -06:00
8 changed files with 281 additions and 130 deletions
+13
View File
@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/.idea.borgScripts.iml
/modules.xml
/contentModel.xml
/projectSettingsUpdater.xml
# Datasource local storage ignored files
/../../../../../../../../../:\Redirected\Asif\Documents\RiderProjects\borgScripts\.idea\.idea.borgScripts.dir\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
+12
View File
@@ -0,0 +1,12 @@
<component name="ProjectDictionaryState">
<dictionary name="asif">
<words>
<w>borgbackup</w>
<w>borghelper</w>
<w>borgvars</w>
<w>listall</w>
<w>makevars</w>
<w>viewarchive</w>
</words>
</dictionary>
</component>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelUserStore">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="BodyLimit" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectBodySeparation" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectLimit" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
-19
View File
@@ -1,19 +0,0 @@
{
"bookmarks": [
{
"fsPath": "$ROOTPATH$/borghelper.sh",
"bookmarks": [
-1,
151,
168,
-1,
-1,
-1,
-1,
-1,
-1,
105
]
}
]
}
+1 -1
View File
@@ -1,3 +1,3 @@
# borgScripts # borgScripts
Pull various environment variables from a central file and save the typing associated with viewing and restoring borg archives. Scripts that simplify working with borgbackup.
+227 -110
View File
@@ -2,17 +2,30 @@
# #
## borg helper script for viewing and restoring backups ## borg helper script for viewing and restoring backups
##
## script written by Asif Bacchus, last updated May 15, 2021.
##
## The author of this script is not affiliated with 'borgbackup' in any way and
## does not warrant anything about this script, its operation, suitability or
## fitness for use in any environment or under any conditions. You are using
## this script entirely at your own risk.
# #
### trap ### trap
trap trapExit 1 2 3 6 trap trapExit 1 2 3 6
### functions ### functions
cleanup () { cleanup() {
# remove borg temp directory, if it exists # remove borg temp directory, if it exists
# shellcheck disable=SC2154
if [ -d "${borgBaseDir}/tmp" ]; then if [ -d "${borgBaseDir}/tmp" ]; then
if ! rm -rf "${borgBaseDir}/tmp" > /dev/null 2>&1; then if ! rm -rf "${borgBaseDir}/tmp" >/dev/null 2>&1; then
consoleError 3 "Script completed successfully but could not remove temporary directory at $borgBaseDir/tmp. Sorry to be messy." consoleError 3 "Script completed successfully but could not remove temporary directory at '$borgBaseDir/tmp'. Sorry to be messy."
fi
fi
if [ -f "${restorePath}/touch.test" ]; then
if ! rm -f "${restorePath}/touch.test" >/dev/null 2>&1; then
consoleError 5 "Script completed successfully but could not remove test file at '$restorePath/touch.test'. Sorry to be messy."
fi fi
fi fi
} }
@@ -23,135 +36,193 @@ consoleError() {
exit "$1" exit "$1"
} }
textblock() { scriptHelp() {
printf "\n"
textBlock "${bold}Usage: borghelper.sh [parameters]${norm}"
printf "\n"
textBlock "Simple script to read connection parameters from a flat text file and process borg 'info', 'list' and 'restore' commands without the very long command lines that are required when specifying repo names and passwords, etc."
printf "\n"
textBlock "${magenta}The script has the following parameters:${norm}"
printf "\n"
textBlock "${magenta}--- Required Parameters ---${norm}"
printf "\n"
textBlockParams "-v|--vars"
textBlock "Path to the .borgvars file from which to read borg connection information. This is not required if run with '--makevars'."
printf "\n"
textBlock "${magenta}--- Operation Modes ---${norm}"
printf "\n"
textBlockParams "--makevars"
textBlock "Create a sample .borgvars file that you can fill in and use with this script."
textBlockParams "-i|--info"
textBlock "Get information about a specified borg repo archive. Requires you supply '--archive'."
textBlockParams "-l|--list"
textBlock "List contents of a specified borg repo archive. Requires you supply '--archive'. You can optionally specify a file/pattern to search for using '--file'."
textBlockParams "-la|--list-all"
textBlock "List all available archives within the repo specified in your .borgvars file."
textBlockParams "-r|--restore"
textBlock "Restore the specified borg repo archive/file(s). Requires you supply '--archive'."
printf "\n"
textBlock "${magenta}--- Selector Parameters ---${norm}"
printf "\n"
textBlockParams "-a|--archive"
textBlock "The archive within your borg repo you wish to work with."
textBlockParams "--exclude"
textBlock "Pattern (python/borg) of files to exclude from a restore operation."
textBlockParams "-f|--file"
textBlock "Specific file/pattern (python/borg) within an archive for which you want to restore or search. Requires that you supply '--archive'."
textBlockParams "-p|--path"
textBlock "Path to which you want your archive/files restored. This script will attempt to create the directory for you if it does not already exist."
printf "\n"
textBlock "${magenta}--- Restore Options ---${norm}"
printf "\n"
textBlockParams "--progress"
textBlock "Display progress indicator during restore operations. WARNING: This can drastically slow down operations on larger archives!"
textBlockParams "--verbose"
textBlock "List the individual files being processed during restore operations."
printf "\n"
textBlock "${magenta}--- Other Parameters ---${norm}"
printf "\n"
textBlockParams "-h|-?|--help"
textBlock "This help screen."
printf "\n"
exit 0
}
textBlock() {
printf "%s\n" "$1" | fold -w "$width" -s printf "%s\n" "$1" | fold -w "$width" -s
} }
trapExit () { textBlockParams() {
printf "%s%s%s\n" "$cyan" "$1" "$norm"
}
trapExit() {
cleanup cleanup
printf "%s\nScript execution terminated via signal.\n\n%s" "$err" "$norm" printf "%s\nScript execution terminated via signal.\n\n%s" "$err" "$norm"
exit 99 exit 99
} }
### text formatting presets ### text formatting presets
if command -v tput > /dev/null; then if command -v tput >/dev/null; then
bold=$(tput bold)
cyan=$(tput setaf 6)
err=$(tput bold)$(tput setaf 1) err=$(tput bold)$(tput setaf 1)
magenta=$(tput setaf 5)
norm=$(tput sgr0) norm=$(tput sgr0)
width=$(tput cols) width=$(tput cols)
else else
bold=""
cyan=""
err="[ERROR] " err="[ERROR] "
magenta=""
norm="" norm=""
width=80 width=80
fi fi
### pre-requisites ### pre-requisites
# is user root? # is user root?
if [ ! "$( id -u )" -eq 0 ]; then if [ ! "$(id -u)" -eq 0 ]; then
consoleError 1 'You must be root to run this script.' consoleError 1 'You must be root to run this script.'
fi fi
# has a parameter been passed to this script? # has a parameter been passed to this script?
if [ -z "$1" ]; then if [ -z "$1" ]; then
consoleError 1 "No operation requested. Please run this script with '--help' for valid parameters." scriptHelp
fi fi
# process startup parameters # process startup parameters
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case "$1" in case "$1" in
-a|--archive) -a | --archive)
# name of backup archive # name of backup archive
if [ -z "$2" ]; then if [ -z "$2" ]; then
consoleError 1 "Please provide the name of the backup archive you want to work with or use '--list-all' to get a full list." consoleError 1 "Please provide the name of the backup archive you want to work with or use '--list-all' to get a full list."
fi fi
archiveName="$2" archiveName="$2"
shift shift
;; ;;
--exclude) --exclude)
# exclude files from restore # exclude files from restore
if [ -z "$2" ]; then if [ -z "$2" ]; then
consoleError 1 "Please provide a list of exclusions in the proper borg format." consoleError 1 "Please provide a list of exclusions in the proper borg format."
fi fi
exclusions="$2" exclusions="$2"
shift shift
;; ;;
-f|--file) -f | --file)
# specific file to restore # specific file/pattern to restore
if [ -z "$2" ]; then if [ -z "$2" ]; then
consoleError 1 'Please provide the name of the specific file you want to restore.' consoleError 1 'Please provide the name of the specific file/pattern for which you want to restore or search.'
fi fi
fileName="$2" fileName="$2"
shift shift
;; ;;
-h|-\?|--help) -h | -\? | --help)
# display help # display help
printf "\nStill working on the help text :-)\n\n" scriptHelp
exit 0 ;;
;; -i | --info)
-i|--info) # show archive information
# show archive information operation='info'
operation='info' ;;
;; -l | --list)
-l|--list) # list contents of specific backup
# list contents of specific backup operation='viewarchive'
operation='viewarchive' ;;
;;
-la | --list-all)
-la|--list-all) # list all backup archives
# list all backup archives operation='listall'
operation='listall' ;;
;; --makevars)
--makevars) # make a borgvars template file
# make a borgvars template file operation='makevars'
operation='makevars' ;;
;; -p | --path)
-p|--path) # path to restore files
# path to restore files if [ -z "$2" ]; then
if [ -z "$2" ]; then consoleError 1 'Please specify a path where you want files restored.'
consoleError 1 'Please specify a path where you want files restored.' fi
fi restorePath="${2%/}"
restorePath="${2%/}" shift
shift ;;
;; --progress)
--progress) # show progress
# show progress commonOptions="$commonOptions --progress"
commonOptions="$commonOptions --progress" ;;
;; -r | --restore)
-r|--restore) # restore archive/file
# restore archive/file operation='restore'
operation='restore' ;;
;; -v | --vars)
-v|--vars) # location of borgvars file
# location of borgvars file if [ -z "$2" ]; then
if [ -z "$2" ]; then consoleError 1 'Please provide the path to the file with your borg connection information.'
consoleError 1 'Please provide the path to the file with your borg connection information.' elif [ ! -f "$2" ]; then
elif [ ! -f "$2" ]; then consoleError 1 'The specified borg connection information file does not exist.'
consoleError 1 'The specified borg connection information file does not exist.'
exit 1
fi
varsFile="$2"
shift
;;
--verbose)
# display each file being processed
restoreOptions="$restoreOptions --list"
;;
*)
# invalid option
printf "%s\nUnknown option: %s\n" "$err" "$1"
printf "Use '--help' for valid options.\n\n%s" "$norm"
exit 1 exit 1
;; fi
varsFile="$2"
shift
;;
--verbose)
# display each file being processed
restoreOptions="$restoreOptions --list"
;;
*)
# invalid option
printf "%s\nUnknown option: %s\n" "$err" "$1"
printf "Use '--help' for valid options.\n\n%s" "$norm"
exit 1
;;
esac esac
shift shift
done done
### process 'makevars' operation ### process 'makevars' operation
if [ "$operation" = 'makevars' ]; then if [ "$operation" = 'makevars' ]; then
if ! printf "sshKeyFile=\nborgBaseDir=\nborgRepo=\nborgRepoPassword=\nborgRemote=\n" > ./sample.borgvars; then if ! printf "sshKeyFile=\nborgBaseDir=\nborgRepo=\nborgRepoPassword=\nborgRepoKey=\nborgRemote=\n" >./sample.borgvars; then
consoleError 4 'Could not write sample borgvars file.' consoleError 4 'Could not write sample borgvars file.'
else else
exit 0 exit 0
@@ -197,19 +268,49 @@ fi
if [ "$commonOptions" ]; then commonOptions=${commonOptions##[[:space:]]}; fi if [ "$commonOptions" ]; then commonOptions=${commonOptions##[[:space:]]}; fi
if [ "$restoreOptions" ]; then restoreOptions=${restoreOptions##[[:space:]]}; fi if [ "$restoreOptions" ]; then restoreOptions=${restoreOptions##[[:space:]]}; fi
# check/create restore path
if [ "$operation" = 'restore' ]; then
if [ -d "$restorePath" ]; then
# convert to absolute path
restorePath=$(
cd "$restorePath" ||
consoleError 5 'Cannot access specified restore directory.'
pwd -P
)
if ! touch "${restorePath}/touch.test" >/dev/null 2>&1; then
consoleError 5 'Cannot write to specified restore directory.'
fi
else
if ! mkdir -p "${restorePath}" >/dev/null 2>&1; then
consoleError 5 'Cannot create specified restore directory.'
else
# convert to absolute path
restorePath=$(
cd "$restorePath" ||
consoleError 5 'Cannot access specified restore directory.'
pwd -P
)
if ! touch "${restorePath}/touch.test" >/dev/null 2>&1; then
consoleError 5 'Cannot write to specified restore directory.'
fi
fi
fi
fi
### read borg information file ### read borg information file
# check if file was provided as a relative or absolute path # check if file was provided as a relative or absolute path
case "${varsFile}" in case "${varsFile}" in
/*) /*)
# absolute path, no need to rewrite variable # absolute path, no need to rewrite variable
. "${varsFile}" # shellcheck disable=SC1090
;; . "${varsFile}"
*) ;;
# relative path, prepend './' to create absolute path *)
. "./${varsFile}" # relative path, prepend './' to create absolute path
;; # shellcheck disable=SC1090
. "./${varsFile}"
;;
esac esac
# verify borg base directory # verify borg base directory
@@ -221,6 +322,7 @@ fi
export BORG_BASE_DIR="${borgBaseDir%/}" export BORG_BASE_DIR="${borgBaseDir%/}"
## check path to SSH keyfile ## check path to SSH keyfile
# shellcheck disable=SC2154
if [ -z "${sshKeyFile}" ]; then if [ -z "${sshKeyFile}" ]; then
consoleError 2 "$varsFile: 'sshKeyFile' is not specified." consoleError 2 "$varsFile: 'sshKeyFile' is not specified."
elif [ ! -f "${sshKeyFile}" ]; then elif [ ! -f "${sshKeyFile}" ]; then
@@ -229,12 +331,14 @@ fi
export BORG_RSH="ssh -i ${sshKeyFile}" export BORG_RSH="ssh -i ${sshKeyFile}"
# check borg repo connect string # check borg repo connect string
# shellcheck disable=SC2154
if [ -z "${borgRepo}" ]; then if [ -z "${borgRepo}" ]; then
consoleError 2 "$varsFile: 'borgRepo' is not specified." consoleError 2 "$varsFile: 'borgRepo' is not specified."
fi fi
export BORG_REPO="${borgRepo}" export BORG_REPO="${borgRepo}"
# check borg repo password # check borg repo password
# shellcheck disable=SC2154
if [ -n "${borgRepoPassword}" ]; then if [ -n "${borgRepoPassword}" ]; then
export BORG_PASSPHRASE="${borgRepoPassword}" export BORG_PASSPHRASE="${borgRepoPassword}"
elif [ "${borgRepoPassword}" = 'none' ]; then elif [ "${borgRepoPassword}" = 'none' ]; then
@@ -243,9 +347,15 @@ else
consoleError 2 "$varsFile: 'borgRepoPassword' must be specified or must be 'none' if no password has been set (VERY INSECURE!)." consoleError 2 "$varsFile: 'borgRepoPassword' must be specified or must be 'none' if no password has been set (VERY INSECURE!)."
fi fi
# export borg remote path, if specified # check borg keyfile if supplied
if [ -n "${borgRemote}" ]; then export BORG_REMOTE_PATH="${borgRemote}"; fi # shellcheck disable=SC2154
if [ -n "${borgRepoKey}" ]; then
export BORG_KEY_FILE="${borgRepoKey}"
fi
# export borg remote path, if specified
# shellcheck disable=SC2154
if [ -n "${borgRemote}" ]; then export BORG_REMOTE_PATH="${borgRemote}"; fi
### create borg temp dir: ### create borg temp dir:
## python requires a writable temporary directory when unpacking borg and ## python requires a writable temporary directory when unpacking borg and
@@ -261,7 +371,6 @@ if [ ! -d "${borgBaseDir}/tmp" ]; then
fi fi
export TMPDIR="${borgBaseDir}/tmp" export TMPDIR="${borgBaseDir}/tmp"
### execute borg operations ### execute borg operations
# info operations # info operations
@@ -271,37 +380,45 @@ if [ "$operation" = 'info' ]; then
elif [ "$operation" = 'listall' ]; then elif [ "$operation" = 'listall' ]; then
borg list borg list
elif [ "$operation" = 'viewarchive' ]; then elif [ "$operation" = 'viewarchive' ]; then
borg list ::"${archiveName}" if [ "$fileName" ]; then
borg list ::"${archiveName}" "${fileName}"
else
borg list ::"${archiveName}"
fi
# restore operations # restore operations
elif [ "$operation" = 'restore' ]; then elif [ "$operation" = 'restore' ]; then
cd "$restorePath" || consoleError 4 'Could not change to restore directory.' cd "$restorePath" || consoleError 4 'Could not change to restore directory.'
if [ -z "$fileName" ]; then if [ -z "$fileName" ]; then
# restore entire archive # restore entire archive
if [ "$exclusions" ]; then if [ "$exclusions" ]; then
# shellcheck disable=SC2086
borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" --exclude "${exclusions}" borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" --exclude "${exclusions}"
else else
# shellcheck disable=SC2086
borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}"
fi fi
elif [ "$fileName" ]; then elif [ "$fileName" ]; then
# restore file/pattern # restore file/pattern
if [ "$exclusions" ]; then if [ "$exclusions" ]; then
# shellcheck disable=SC2086
borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" "${fileName}" --exclude "${exclusions}" borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" "${fileName}" --exclude "${exclusions}"
else else
# shellcheck disable=SC2086
borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" "${fileName}" borg --show-rc ${commonOptions} extract ${restoreOptions} ::"${archiveName}" "${fileName}"
fi fi
fi fi
fi fi
### exit gracefully ### exit gracefully
cleanup cleanup
exit 0 exit 0
### exit codes ### exit codes
# 0: no errors, script completed successfully # 0: no errors, script completed successfully
# 1: parameter error (missing, non-existant or invalid input) # 1: parameter error (missing, non-existent or invalid input)
# 2: parameter missing/invalid in .borgvars file # 2: parameter missing/invalid in .borgvars file
# 3: could not create/remove borg tmp directory # 3: could not create/remove borg tmp directory
# 4: could not write sample borgvars file (permissions?)
# 5: cannot access/create/write to restore path or could not remove test file
#EOF #EOF