#compdef borg # ------- # # To Install: # # Copy this file to /usr/share/zsh/site-functions/ # # ------- # borgbackup ZSH completion # Kevin Gravier 2017 # # The MIT License (MIT) # Copyright (c) 2017 Kevin # 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. _borg() { typeset -A opt_args local -a borg_possible_commands borg_possible_key_commands commands keyCommands borg_common_options local command keyCommand item subItem borg_common_options=({-h,--help}'[show this help message and exit]' --critical'[work on log level CRITICAL]' --error'[work on log level ERROR]' --warning'[work on log level WARNING (default)]' {--info,-v,--verbose}'[work on log level INFO]' --debug'[work on log level DEBUG]' --default-topic'[enable TOPIC debugging (can be specified multiple times).]:TOPIC' {-p,--progress}'[show progress information]' --log-json'[Output one JSON object per log line instead of formatted text.]' --lock-wait'[wait at most SECONDS for acquiring a repository/cache lock (default: 1).]:SECONDS' --show-version'[show/log the borg version]' --show-rc'[show/log the return code (rc)]' --umask'[set umask to M (local and remote, default: 0077)]:umask' --remote-path'[set remote path to executable (default: "borg")]:_files' --remote-ratelimit'[set remote network upload rate limit in kiByte/s (default: 0=unlimited)]:RATE' --consider-part-files'[treat part files like normal files (e.g. to list/extract them)]' --debug-profile'[Write execution profile in Borg format into FILE.]:_files') borg_possible_commands=(init create extract check rename list diff delete prune info mount umount key upgrade recreate export-tar serve config with-lock break-lock benchmark) borg_possible_key_commands=(change-passphrase import export) command="" keyCommand="" for item in $words; do (( ${borg_possible_commands[(I)$item]} )) && command=$item (( ${borg_possible_key_commands[(I)$item]} )) && keyCommand=$item done case $command in (init) _arguments \ '2:repo:_files'\ {-e,--encryption}'[select encryption key mode]:MODE'\ --append-only'[only allow appending to repository segment files]'\ --storage-quota'[Override storage quota of the repository]:QUOTA'\ $borg_common_options ;; (create) _arguments \ '2:archives:__borg_archive'\ '3:path:_files'\ {-n,--dry-run}'[do not create a backup archive]'\ {-s,--stats}'[print statistics for the created archive]'\ --list'[output verbose list of items (files, dirs, ...)]'\ --filter'[only display items with the given status characters]:STATUSCHARS'\ --json'[output stats as JSON. Implies --stats.]'\ --no-cache-sync'[experimental: do not synchronize the cache. Implies not using the files cache.]'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ --exclude-caches'[exclude directories that contain a CACHEDIR.TAG file ]'\ --exclude-if-present'[exclude directories that are tagged by containing a filesystem object with the given NAME]:NAME'\ {--keep-exclude-tags,--keep-tag-files}'[if tag objects are specified with --exclude-if-present, don’t omit the tag objects themselves]'\ {-x,--one-file-system}'[stay in the same file system ]'\ --numeric-owner'[only store numeric user and group identifiers]'\ --noatime'[do not store atime into archive]'\ --nobirthtime'[do not store birthtime (creation date) into archive]'\ --nobsdflags'[do not read and store bsdflags (e.g. NODUMP, IMMUTABLE) into archive]'\ --ignore-inode'[ignore inode data in the file metadata cache used to detect unchanged files.]'\ --files-cache'[operate files cache in MODE. default: ctime,size,inode]:MODE'\ --read-special'[open and read block and char device files as well as FIFOs as if they were regular files.]'\ --comment'[add a comment text to the archive]:COMMENT'\ --timestamp'[manually specify the archive creation date/time]:TIMESTAMP'\ --timestamp'[manually specify the archive creation date/time by a reference file/directory]:_files'\ {-c,--checkpoint-interval}'[write checkpoint every SECONDS seconds]:SECONDS'\ --chunker-params'[specify the chunker parameters]:PARAMS'\ {-C,--compression}'[select compression algorithm]:COMPRESSION'\ $borg_common_options ;; (extract) _arguments \ '2:archives:__borg_archive'\ '3:path:_files'\ --list'[output verbose list of items (files, dirs, ...)]'\ {-n,--dry-run}'[do not actually change any files]'\ --numeric-owner'[only obey numeric user and group identifiers]'\ --nobsdflags'[do not extract/set bsdflags (e.g. NODUMP, IMMUTABLE)]'\ --stdout'[write all extracted data to stdout]'\ --sparse'[create holes in output sparse file from all-zero chunks]'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ --strip-components'[Remove the specified number of leading path elements. Paths with fewer elements will be silently skipped.]:NUMBER'\ $borg_common_options ;; (check) _arguments \ '2:archives:__borg_archive'\ --repository-only'[only perform repository checks]'\ --archives-only'[only perform archives checks]'\ --verify-data'[perform cryptographic archive data integrity verification]'\ --repair'[attempt to repair any inconsistencies found]'\ --save-space'[work slower, but using less space]'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ --sort-by'[Comma-separated list of sorting keys]:KEYS'\ --first'[consider first N archives after other filters were applied]:N'\ --last'[consider last N archives after other filters were applied]:N'\ $borg_common_options ;; (rename) _arguments \ '2:archives:__borg_archive'\ '3:name:NAME'\ $borg_common_options ;; (list) _arguments \ '2:archives:__borg_archive'\ '*:path:_files'\ --short'[only print file/directory names, nothing else]'\ {--format,--list-format}'[specify format for file listing]:FORMAT'\ --json'[Only valid for listing repository contents. Format output as JSON.]'\ --json-lines'[Only valid for listing archive contents. Format output as JSON Lines. ]'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ --sort-by'[Comma-separated list of sorting keys]:KEYS'\ --first'[consider first N archives after other filters were applied]:N'\ --last'[consider last N archives after other filters were applied]:N'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ $borg_common_options ;; (diff) _arguments \ '2:archives:__borg_archive'\ '3:archives:__borg_archive'\ '*:path:_files'\ --numeric-owner'[only obey numeric user and group identifiers]'\ --same-chunker-params'[override check of chunker parameters.]'\ --sort'[sort the output lines by file path.]'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ $borg_common_options ;; (delete) _arguments \ '2:archives:__borg_archive'\ '*:archives:archives'\ {-s,--stats}'[print statistics for the deleted archive]'\ --cache-only'[delete only the local cache for the given repository]'\ --force'[force deletion of corrupted archives, use --force --force in case --force does not work.]'\ --save-space'[work slower, but using less space]'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ --sort-by'[Comma-separated list of sorting keys]:KEYS'\ --first'[consider first N archives after other filters were applied]:N'\ --last'[consider last N archives after other filters were applied]:N'\ $borg_common_options ;; (prune) _arguments \ '2:archives:__borg_archive'\ {-n,--dry-run}'[do not change repository]'\ --force'[force pruning of corrupted archives]'\ {-s,--stats}'[print statistics for the deleted archive]'\ --list'[output verbose list of archives it keeps/prunes]'\ --keep-within'[keep all archives within this time interval]:INTERVAL'\ {--keep-last,--keep-secondly}'[number of secondly archives to keep]:N'\ --keep-minutely'[number of minutely archives to keep]:N'\ {-H,--keep-hourly}'[number of hourly archives to keep]:N'\ {-d,--keep-daily}'[number of daily archives to keep]:N'\ {-w,--keep-weekly}'[number of weekly archives to keep]:N'\ {-m,--keep-monthly}'[number of monthly archives to keep]:N'\ {-y,--keep-yearly}'[number of yearly archives to keep]:N'\ --save-space'[work slower, but using less space]'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ $borg_common_options ;; (info) _arguments \ '2:archives:__borg_archive'\ --json'[format output as JSON]'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ --sort-by'[Comma-separated list of sorting keys]:KEYS'\ --first'[consider first N archives after other filters were applied]:N'\ --last'[consider last N archives after other filters were applied]:N'\ $borg_common_options ;; (mount) _arguments \ '2:archives:__borg_archive'\ '3:mountpoint:_files'\ {-f,--foreground}'[stay in foreground, do not daemonize]'\ -o'[Extra mount options]:OPTS'\ {-P,--prefix}'[only consider archive names starting with this prefix.]:PREFIX'\ {-a,--glob-archives}'[only consider archive names matching the glob]:GLOB'\ --sort-by'[Comma-separated list of sorting keys]:KEYS'\ --first'[consider first N archives after other filters were applied]:N'\ --last'[consider last N archives after other filters were applied]:N'\ $borg_common_options ;; (umount) _arguments \ '2:mountpoint:_files'\ $borg_common_options ;; (key) case $keyCommand in (change-passphrase) _arguments \ '2:subCommand:(change-passphrase import export)'\ '3:archives:__borg_archive'\ $borg_common_options ;; (export) _arguments \ '2:subCommand:(change-passphrase import export)'\ '3:archives:__borg_archive'\ '4:path:_files'\ --paper'[Create an export suitable for printing and later type-in]'\ --qr-html'[Create an html file suitable for printing and later type-in or qr scan]'\ $borg_common_options ;; (import) _arguments \ '2:subCommand:(change-passphrase import export)'\ '3:archives:__borg_archive'\ '4:path:_files'\ --paper'[interactively import from a backup done with --paper]'\ $borg_common_options ;; *) _arguments \ '2:subCommand:(change-passphrase import export)'\ $borg_common_options ;; esac ;; (upgrade) _arguments \ '2:archives:__borg_archive'\ {-n,--dry-run}'[do not change repository]'\ --inplace'[rewrite repository in place, with no chance of going back to older versions of the repository.]'\ --force'[Force upgrade]'\ --tam'[Enable manifest authentication (in key and cache).]'\ --disable-tam'[Disable manifest authentication (in key and cache).]'\ $borg_common_options ;; (recreate) _arguments \ '2:archives:__borg_archive'\ '3:path:_files'\ --list'[output verbose list of items (files, dirs, ...)]'\ --filter'[only display items with the given status characters]:STATUSCHARS'\ {-n,--dry-run}'[do not create a backup archive]'\ {-s,--stats}'[print statistics at end]'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ --exclude-caches'[exclude directories that contain a CACHEDIR.TAG file ]'\ --exclude-if-present'[exclude directories that are tagged by containing a filesystem object with the given NAME]:NAME'\ {--keep-exclude-tags,--keep-tag-files}'[if tag objects are specified with --exclude-if-present, don’t omit the tag objects themselves]'\ --target'[create a new archive with the name ARCHIVE]:ARCHIVE'\ {-c,--checkpoint-interval}'[write checkpoint every SECONDS seconds]:SECONDS'\ --comment'[add a comment text to the archive]:COMMENT'\ --timestamp'[manually specify the archive creation date/time]:TIMESTAMP'\ {-C,--compression}'[select compression algorithm]:COMPRESSION'\ --recompress'[recompress data chunks according to --compression if if-different]:PARAMS'\ --chunker-params'[pecify the chunker parameters]:PARAMS'\ $borg_common_options ;; (export-tar) _arguments \ '2:archives:__borg_archive'\ '3:tar:_files'\ '4:path:_files'\ --tar-filter'[filter program to pipe data through]'\ --list'[output verbose list of items (files, dirs, ...)]'\ {-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\ --exclude-from'[read exclude patterns from EXCLUDEFILE, one per line]:_files'\ --pattern'[experimental: include/exclude paths matching PATTERN]:PATTERN'\ --patterns-from'[experimental: read include/exclude patterns from PATTERNFILE, one per line]:_files'\ --strip-components'[Remove the specified number of leading path elements. Paths with fewer elements will be silently skipped.]:NUMBER'\ $borg_common_options ;; (serve) _arguments \ --restrict-to-path'[restrict repository access to PATH]:_files'\ --restrict-to-repository'[restrict repository access]:_files'\ --append-only'[only allow appending to repository segment files]'\ --storage-quota'[Override storage quota of the repository]:QUOTA'\ $borg_common_options ;; (config) _arguments \ '2:archives:__borg_archive'\ '3:name:NAME'\ '4:value:VALUE'\ {-c,--cache}'[get and set values from the repo cache]'\ {-d,--delete}'[delete the key from the config file]'\ $borg_common_options ;; (with-lock) _arguments \ '(-)2:archives:__borg_archive'\ $borg_common_options #'3:command:_command_names -e'\ #'4:arguments:_normal' #TODO Debug this, getting "_tags:comptags:36: nesting level too deep" error ;; (break-lock) _arguments \ '2:archives:__borg_archive'\ $borg_common_options ;; (benchmark) _arguments \ '2:type:(crud)'\ '3:repo:_files'\ '4:path:_files'\ $borg_common_options ;; *) commands=( 'init:initialize empty repository' 'create:create backup' 'extract:extract archive contents' 'check:verify repository' 'rename:rename archive' 'list:list archive or repository contents' 'diff:find differences in archive contents' 'delete:delete archive' 'prune:prune archives' 'info:show repository or archive information' 'mount:mount repository' 'umount:umount repository' 'key:manage repository key' 'upgrade:upgrade repository format' 'recreate:recreate contents of existing archives' 'export-tar:create tarball from archive' 'serve:start repository server process' 'config:get/set options in repo/cache config' 'with-lock:run user command with lock held' 'break-lock:break repository and cache locks' 'benchmark:benchmark command' ) _describe 'values' commands _arguments $borg_common_options ;; esac } __borg_archive() { local -a items if (($+BORG_REPO)); then items=("${(@f)$(borg list $cpath --short 2>/dev/null | sed "s#^#::#")}") else local cpath cpath=$words[-1] cpath=${cpath%::*} items=("${(@f)$(borg list $cpath --short 2>/dev/null | sed "s#^#${cpath}::#")}") fi if [[ $items[1] == "" ]]; then _files -/ else _wanted archives expl 'archive' compadd $items fi }