_borg 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627
  1. #compdef borg borgfs -P -value-,BORG_*,-default-
  2. # Zsh completion for Borg Backup 1.1.17.
  3. #
  4. # Recommended _borg specific settings:
  5. #
  6. # zstyle -e ':completion:*:*:borg-*:argument-rest:*' tag-order \
  7. # '[[ $words[CURRENT] == -* ]] && reply=( "! archives archive-files" "-" )'
  8. # zstyle ':completion:*:*:(borg|-value-,BORG_)*' sort false
  9. # zstyle ':completion:*:*:borg-config:argument-2:keys' list-grouped false
  10. # zstyle ':completion:*:*:borg-*:*' gain-privileges true
  11. # zstyle ':completion:*' fake-parameters 'BORG_REPO:scalar'
  12. #
  13. # Custom styles:
  14. #
  15. # archive-description-format
  16. # Default: `{archive:<36} {time} [{id}]`.
  17. # archive-sort
  18. # In which order archive names should be listed.
  19. # Possible values are: `inverse`, `timestamp`, `name`, `id`.
  20. # file-description-format
  21. # Default: `{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}`.
  22. # path-style-selector
  23. # Style selector used to select a path (when Borg would use either `pp` or `pf`).
  24. # Default: `fm`.
  25. # repository-suffix
  26. # This boolean style controls whether to add the `::` auto-removable suffix to a repository.
  27. # Default: `true`.
  28. (( $+functions[_borg_commands] )) ||
  29. _borg_commands() {
  30. local -a commands_=(
  31. 'benchmark:benchmark command'
  32. 'break-lock:break repository and cache locks'
  33. 'change-passphrase:change repository passphrase'
  34. 'check:verify repository'
  35. 'config:get and set configuration values'
  36. 'create:create backup'
  37. 'debug:debugging command (not intended for normal use)'
  38. 'delete:delete archive'
  39. 'diff:find differences in archive contents'
  40. 'export-tar:create tarball from archive'
  41. 'extract:extract archive contents'
  42. 'help:extra help'
  43. 'info:show repository or archive information'
  44. 'init:initialize empty repository'
  45. 'key:manage repository key'
  46. 'list:list archive or repository contents'
  47. 'mount:mount repository'
  48. 'prune:prune archives'
  49. 'recreate:re-create archives'
  50. 'rename:rename archive'
  51. 'serve:start repository server process'
  52. 'umount:umount repository'
  53. 'upgrade:upgrade repository format'
  54. 'with-lock:run user command with lock held'
  55. )
  56. _describe -t commands 'borg commands' commands_
  57. }
  58. (( $+functions[_borg-benchmark] )) ||
  59. _borg-benchmark() {
  60. local -a common_options
  61. __borg_setup_common_options
  62. _arguments -s -w -S : \
  63. $common_options \
  64. ':type:(crud)' \
  65. ': :_borg_repository' \
  66. ':PATH:_files'
  67. }
  68. (( $+functions[_borg-break-lock] )) ||
  69. _borg-break-lock() {
  70. local -a common_options
  71. __borg_setup_common_options
  72. _arguments -s -w -S : \
  73. $common_options \
  74. ':: :_borg_repository'
  75. }
  76. (( $+functions[_borg-change-passphrase] )) ||
  77. _borg-change-passphrase() {
  78. local -a common_options
  79. __borg_setup_common_options
  80. _arguments -s -w -S : \
  81. $common_options \
  82. ':: :_borg_repository'
  83. }
  84. (( $+functions[_borg-check] )) ||
  85. _borg-check() {
  86. local -a common_options common_archive_filters_options
  87. __borg_setup_common_options
  88. __borg_setup_common_archive_filters_options
  89. _arguments -s -w -S : \
  90. '--repository-only[only perform repository checks]' \
  91. '--archives-only[only perform archives checks]' \
  92. '(--repository-only)--verify-data[perform cryptographic archive data integrity verification]' \
  93. '--repair[attempt to repair any inconsistencies found]' \
  94. '--save-space[work slower, but using less space]' \
  95. $common_archive_filters_options \
  96. $common_options \
  97. '::REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive'
  98. }
  99. (( $+functions[_borg-config] )) ||
  100. _borg-config() {
  101. local -a common_options
  102. __borg_setup_common_options
  103. _arguments -s -w -S : \
  104. '(-c --cache)'{-c,--cache}'[get and set values from the repo cache]' \
  105. '(-d --delete)'{-d,--delete}'[delete the key from the config]' \
  106. '(-l --list)'{-l,--list}'[list the configuration of the repo]' \
  107. $common_options \
  108. ': :_borg_repository' \
  109. ': : _borg_config $line[1]' \
  110. '::VALUE'
  111. }
  112. (( $+functions[_borg-create] )) ||
  113. _borg-create() {
  114. local -a common_options common_create_options
  115. __borg_setup_common_options
  116. __borg_setup_common_create_options
  117. _arguments -s -w -S : \
  118. '*'{-e,--exclude}'=[exclude paths matching PATTERN]: : _borg_style_selector_or_archive_files -f -e "$line[1]" fm "${(@)line[2,-1]}"' \
  119. '*--pattern=[experimental: include/exclude paths matching PATTERN]: : _borg_style_selector_or_archive_files -p -f -e "$line[1]" sh "${(@)line[2,-1]}"' \
  120. $common_create_options \
  121. '(-s --stats)--json[Output stats as JSON. Implies --stats.]' \
  122. '--no-cache-sync[experimental: do not synchronize the cache. Implies not using the files cache.]' \
  123. '--no-files-cache[do not load/update the file metadata cache used to detect unchanged files]' \
  124. '--stdin-name=[use NAME in archive for stdin data (default: "stdin")]:NAME' \
  125. '--stdin-user=[set user USER in archive for stdin data (default: root)]:USER:_users' \
  126. '--stdin-group=[set group GROUP in archive for stdin data (default: root)]:GROUP:_groups' \
  127. '--stdin-mode=[set mode to M in archive for stdin data (default: 0660)]: : _borg_guard_numeric_mode "M"' \
  128. '--exclude-nodump[exclude files flagged NODUMP]' \
  129. '(-x --one-file-system)'{-x,--one-file-system}'[stay in the same file system]' \
  130. '--numeric-owner[only store numeric user and group identifiers]' \
  131. '--noatime[do not store atime into archive]' \
  132. '--noctime[do not store ctime into archive]' \
  133. '--nobirthtime[do not store birthtime (creation date) into archive]' \
  134. '--nobsdflags[do not read and store bsdflags (e.g. NODUMP, IMMUTABLE) into archive]' \
  135. '--noacls[do not read and store ACLs into archive]' \
  136. '--noxattrs[do not read and store xattrs into archive]' \
  137. '--ignore-inode[ignore inode data in the file metadata cache used to detect unchanged files]' \
  138. '--files-cache=[operate files cache in MODE. default: ctime,size,inode]:MODE:(ctime,size,inode mtime,size,inode ctime,size mtime,size rechunk,ctime rechunk,mtime size disabled)' \
  139. '--read-special[open and read block and char device files as well as FIFOs as if they were regular files]' \
  140. $common_options \
  141. ':ARCHIVE: _borg_repository_or_archive -a -p' \
  142. '*:PATH:_files'
  143. }
  144. (( $+functions[_borg-debug] )) ||
  145. _borg-debug() {
  146. local -a state line common_options
  147. local curcontext="$curcontext" state_descr
  148. declare -A opt_args
  149. local -i ret=1
  150. __borg_setup_common_options
  151. _arguments -s -w -C : \
  152. $common_options \
  153. ': :->command' \
  154. '*:: :->option-or-argument' && ret=0
  155. case $state in
  156. (command)
  157. local -a debug_commands=(
  158. 'info:show system infos for debugging / bug reports'
  159. 'dump-archive-items:dump archive items (metadata)'
  160. 'dump-archive:dump decoded archive metadata'
  161. 'dump-manifest:dump decoded repository metadata'
  162. 'dump-repo-objs:dump repo objects'
  163. 'search-repo-objs:search repo objects'
  164. 'get-obj:get object from repository'
  165. 'put-obj:put object to repository'
  166. 'delete-obj:delete object from repository'
  167. 'refcount-obj:show refcount for object from repository'
  168. 'dump-hints:dump repository hints'
  169. 'convert-profile:convert Borg profile to Python profile'
  170. )
  171. _describe -t commands 'command' debug_commands && ret=0
  172. ;;
  173. (option-or-argument)
  174. curcontext="${curcontext%:*}-$line[1]:"
  175. case $line[1] in
  176. (info)
  177. _arguments -s -w -S : \
  178. $common_options && ret=0
  179. ;;
  180. (dump-archive-items)
  181. _arguments -s -w -S : \
  182. $common_options \
  183. ':ARCHIVE: _borg_repository_or_archive -a' && ret=0
  184. ;;
  185. (dump-archive)
  186. _arguments -s -w -S : \
  187. $common_options \
  188. ':ARCHIVE: _borg_repository_or_archive -a' \
  189. ':PATH:_files' && ret=0
  190. ;;
  191. (dump-manifest)
  192. _arguments -s -w -S : \
  193. $common_options \
  194. ': :_borg_repository' \
  195. ':PATH:_files' && ret=0
  196. ;;
  197. (dump-repo-objs)
  198. _arguments -s -w -S : \
  199. $common_options \
  200. ': :_borg_repository' && ret=0
  201. ;;
  202. (search-repo-objs)
  203. _arguments -s -w -S : \
  204. $common_options \
  205. ': :_borg_repository' \
  206. ':WANTED (hex or string):' && ret=0
  207. ;;
  208. (get-obj)
  209. _arguments -s -w -S : \
  210. $common_options \
  211. ': :_borg_repository' \
  212. ':ID (hex object):' \
  213. ':PATH:_files' && ret=0
  214. ;;
  215. (put-obj)
  216. _arguments -s -w -S : \
  217. $common_options \
  218. ': :_borg_repository' \
  219. '*:PATH:_files' && ret=0
  220. ;;
  221. (delete-obj)
  222. _arguments -s -w -S : \
  223. $common_options \
  224. ': :_borg_repository' \
  225. '*:ID (hex object):' && ret=0
  226. ;;
  227. (refcount-obj)
  228. _arguments -s -w -S : \
  229. $common_options \
  230. ': :_borg_repository' \
  231. '*:ID (hex object):' && ret=0
  232. ;;
  233. (dump-hints)
  234. _arguments -s -w -S : \
  235. $common_options \
  236. ': :_borg_repository' \
  237. '*:PATH:_files' && ret=0
  238. ;;
  239. (convert-profile)
  240. _arguments -s -w -S : \
  241. $common_options \
  242. ':INPUT:_files' \
  243. ':OUTPUT:_files' && ret=0
  244. ;;
  245. (*)
  246. if ! _call_function ret _borg_debug_$line[1]; then
  247. _default && ret=0
  248. fi
  249. ;;
  250. esac
  251. ;;
  252. esac
  253. return ret
  254. }
  255. (( $+functions[_borg-delete] )) ||
  256. _borg-delete() {
  257. local -a common_options common_archive_filters_options common_dry_run_stats_options
  258. __borg_setup_common_options
  259. __borg_setup_common_archive_filters_options
  260. __borg_setup_common_dry_run_stats_options
  261. _arguments -s -w -S : \
  262. $common_dry_run_stats_options \
  263. '--cache-only[delete only the local cache for the given repository]' \
  264. '*--force[force deletion of corrupted archives, use "--force --force" in case "--force" does not work]' \
  265. '--save-space[work slower, but using less space]' \
  266. $common_archive_filters_options \
  267. $common_options \
  268. ':REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive' \
  269. '*:ARCHIVE: _borg_archive "${line[1]%%::*}"'
  270. }
  271. (( $+functions[_borg-diff] )) ||
  272. _borg-diff() {
  273. local -a common_options common_exclude_options
  274. __borg_setup_common_options
  275. __borg_setup_common_exclude_options
  276. _arguments -s -w -S : \
  277. '--numeric-owner[only obey numeric user and group identifiers]' \
  278. '--same-chunker-params[override check of chunker parameters]' \
  279. '--sort[sort the output lines by file path]' \
  280. '--json-lines[format output as JSON Lines]' \
  281. $common_exclude_options \
  282. $common_options \
  283. ':ARCHIVE1: _borg_repository_or_archive -a' \
  284. ':ARCHIVE2: _borg_archive "${line[1]%%::*}"' \
  285. '*: : _borg_style_selector_or_archive_files -e "$line[1]" pp'
  286. }
  287. (( $+functions[_borg-export-tar] )) ||
  288. _borg-export-tar() {
  289. local -a common_options common_exclude_extract_options
  290. __borg_setup_common_options
  291. __borg_setup_common_exclude_extract_options
  292. _arguments -s -w -S : \
  293. '--tar-filter[filter program to pipe data through]: :_cmdstring' \
  294. '--list[output verbose list of items (files, dirs, ...)]' \
  295. $common_exclude_extract_options \
  296. $common_options \
  297. ':ARCHIVE: _borg_repository_or_archive -a' \
  298. ':FILE:_files' \
  299. '*: : _borg_style_selector_or_archive_files -e "$line[1]" pp'
  300. }
  301. (( $+functions[_borg-extract] )) ||
  302. _borg-extract() {
  303. local -a common_options common_exclude_extract_options
  304. __borg_setup_common_options
  305. __borg_setup_common_exclude_extract_options
  306. _arguments -s -w -S : \
  307. '--list[output verbose list of items (files, dirs, ...)]' \
  308. '(-n --dry-run)'{-n,--dry-run}'[do not actually change any files]' \
  309. '--numeric-owner[only obey numeric user and group identifiers]' \
  310. '--nobsdflags[do not extract/set bsdflags (e.g. NODUMP, IMMUTABLE)]' \
  311. '--noacls[do not extract/set ACLs]' \
  312. '--noxattrs[do not extract/set xattrs]' \
  313. '--stdout[write all extracted data to stdout]' \
  314. '--sparse[create holes in output sparse file from all-zero chunks]' \
  315. $common_exclude_extract_options \
  316. $common_options \
  317. ':ARCHIVE: _borg_repository_or_archive -a' \
  318. '*: : _borg_style_selector_or_archive_files -e "$line[1]" pp'
  319. }
  320. (( $+functions[_borg-help] )) ||
  321. _borg-help() {
  322. local -a common_options
  323. __borg_setup_common_options
  324. _arguments -s -w -S : \
  325. '--epilog-only' \
  326. '--usage-only' \
  327. $common_options \
  328. ':: : _alternative "topics:TOPIC:(patterns placeholders compression)" ": :_borg_commands"'
  329. }
  330. (( $+functions[_borg-info] )) ||
  331. _borg-info() {
  332. local -a common_options common_archive_filters_options
  333. __borg_setup_common_options
  334. __borg_setup_common_archive_filters_options
  335. _arguments -s -w -S : \
  336. '--json[format output as JSON]' \
  337. $common_archive_filters_options \
  338. $common_options \
  339. '::REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive'
  340. }
  341. (( $+functions[_borg-init] )) ||
  342. _borg-init() {
  343. local -i ret=1
  344. local -a common_options common_init_options
  345. __borg_setup_common_options
  346. __borg_setup_common_init_options
  347. # special handling for the required optional argument
  348. if (( ! ${words[(I)(-e|--encryption)(|=*)]} )); then
  349. local desc='select encryption key mode'
  350. local -a long=( "--encryption:$desc" ) short=( "-e:$desc" ) remove_chars=( -r '= \t\n\-' )
  351. _describe -t required-options 'required option' long -S '=' $remove_chars -- short $remove_chars && ret=0
  352. fi
  353. _arguments -s -w -S : \
  354. '(-e --encryption)'{-e,--encryption}'=[select encryption key mode (required)]:MODE:(none keyfile keyfile-blake2 repokey repokey-blake2 authenticated authenticated-blake2)' \
  355. $common_init_options \
  356. '--make-parent-dirs[create parent directories]' \
  357. '::REPOSITORY:_directories' && ret=0
  358. return ret
  359. }
  360. (( $+functions[_borg-key] )) ||
  361. _borg-key() {
  362. local -a state line common_options
  363. local curcontext="$curcontext" state_descr
  364. declare -A opt_args
  365. local -i ret=1
  366. __borg_setup_common_options
  367. _arguments -s -w -C : \
  368. $common_options \
  369. ': :->command' \
  370. '*:: :->option-or-argument' && ret=0
  371. case $state in
  372. (command)
  373. local -a key_commands=(
  374. 'change-passphrase:Change repository key file passphrase'
  375. 'export:Export the repository key for backup'
  376. 'import:Import the repository key from backup'
  377. 'migrate-to-repokey:Migrate passphrase -> repokey'
  378. )
  379. _describe -t commands 'command' key_commands && ret=0
  380. ;;
  381. (option-or-argument)
  382. curcontext="${curcontext%:*}-$line[1]:"
  383. case $line[1] in
  384. (change-passphrase)
  385. _arguments -s -w -S : \
  386. $common_options \
  387. ': :_borg_repository' && ret=0
  388. ;;
  389. (export)
  390. _arguments -s -w -S : \
  391. '--paper[create an export suitable for printing and later type-in]' \
  392. '--qr-html[create an html file suitable for printing and later type-in or qr scan]' \
  393. $common_options \
  394. ': :_borg_repository' \
  395. '::PATH:_files' && ret=0
  396. ;;
  397. (import)
  398. _arguments -s -w -S : \
  399. '--paper[interactively import from a backup done with --paper]' \
  400. $common_options \
  401. ': :_borg_repository' \
  402. '::PATH:_files' && ret=0
  403. ;;
  404. (migrate-to-repokey)
  405. _arguments -s -w -S : \
  406. $common_options \
  407. ':: :_borg_repository' && ret=0
  408. ;;
  409. (*)
  410. if ! _call_function ret _borg_key_$line[1]; then
  411. _default && ret=0
  412. fi
  413. ;;
  414. esac
  415. ;;
  416. esac
  417. return ret
  418. }
  419. (( $+functions[_borg-list] )) ||
  420. _borg-list() {
  421. local -a common_options common_exclude_options common_archive_filters_options
  422. __borg_setup_common_options
  423. __borg_setup_common_exclude_options
  424. __borg_setup_common_archive_filters_options
  425. _arguments -s -w -S : \
  426. '--short[only print file/directory names, nothing else]' \
  427. {--format,--list-format}'=[specify format for file listing]:FORMAT: _borg_format_keys $line[1]' \
  428. '--json[Only valid for listing repository contents. Format output as JSON.]' \
  429. '--json-lines[Only valid for listing archive contents. Format output as JSON Lines.]' \
  430. $common_archive_filters_options \
  431. $common_exclude_options \
  432. $common_options \
  433. ':REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive' \
  434. '*: : _borg_style_selector_or_archive_files -e "$line[1]" pp'
  435. }
  436. (( $+functions[_borg-mount] )) ||
  437. _borg-mount() {
  438. local -a common_options common_exclude_extract_options common_archive_filters_options
  439. __borg_setup_common_options
  440. __borg_setup_common_exclude_extract_options
  441. __borg_setup_common_archive_filters_options
  442. _arguments -s -w -S : \
  443. $* \
  444. '(-f --foreground)'{-f,--foreground}'[stay in foreground, do not daemonize]' \
  445. '-o[mount options]: :_fuse_values "mount options"
  446. "versions[merged, versioned view of the files in the archives]"
  447. "allow_damaged_files[read damaged files]"
  448. "ignore_permissions[not enforce \"default_permissions\"]"' \
  449. $common_archive_filters_options \
  450. $common_exclude_extract_options \
  451. $common_options \
  452. ':REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive' \
  453. ':MOUNTPOINT:_directories' \
  454. '*: : _borg_style_selector_or_archive_files "$line[1]" pp'
  455. }
  456. (( $+functions[_borg-prune] )) ||
  457. _borg-prune() {
  458. local -a common_options common_prefix_and_glob_archives_filter_options common_dry_run_stats_options
  459. __borg_setup_common_options
  460. __borg_setup_common_prefix_and_glob_archives_filter_options
  461. __borg_setup_common_dry_run_stats_options
  462. _arguments -s -w -S : \
  463. $common_dry_run_stats_options \
  464. '*--force[force pruning of corrupted archives, use "--force --force" in case "--force" does not work]' \
  465. '--list[output verbose list of archives it keeps/prunes]' \
  466. '--keep-within[keep all archives within this time interval]: : _borg_guard_unsigned_number "INTERVAL"' \
  467. '(--keep-last --keep-secondly)'{--keep-last,--keep-secondly}'[number of secondly archives to keep]: : _borg_guard_unsigned_number "N"' \
  468. '--keep-minutely[number of minutely archives to keep]: : _borg_guard_unsigned_number "N"' \
  469. '(-H --keep-hourly)'{-H,--keep-hourly}'[number of hourly archives to keep]: : _borg_guard_unsigned_number "N"' \
  470. '(-d --keep-daily)'{-d,--keep-daily}'[number of daily archives to keep]: : _borg_guard_unsigned_number "N"' \
  471. '(-w --keep-weekly)'{-w,--keep-weekly}'[number of weekly archives to keep]: : _borg_guard_unsigned_number "N"' \
  472. '(-m --keep-monthly)'{-m,--keep-monthly}'[number of monthly archives to keep]: : _borg_guard_unsigned_number "N"' \
  473. '(-y --keep-yearly)'{-y,--keep-yearly}'[number of yearly archives to keep]: : _borg_guard_unsigned_number "N"' \
  474. '--save-space[work slower, but using less space]' \
  475. $common_prefix_and_glob_archives_filter_options \
  476. $common_options \
  477. ':: :_borg_repository'
  478. }
  479. (( $+functions[_borg-recreate] )) ||
  480. _borg-recreate() {
  481. local -a common_options common_create_options
  482. __borg_setup_common_options
  483. __borg_setup_common_create_options
  484. local -a mods=(
  485. 'if-different:recompress if current compression is with a different compression algorithm (the level is not considered)'
  486. 'always:recompress even if current compression is with the same compression algorithm (use this to change the compression level)'
  487. 'never:do not recompress (use this option to explicitly prevent recompression)'
  488. )
  489. mods=( ${${(q)mods//\\/\\\\}//:/\\:} )
  490. _arguments -s -w -S : \
  491. $common_create_options \
  492. '--target=[create a new archive with the name ARCHIVE]:ARCHIVE: _borg_placeholder_or_archive "${line[1]%%\:\:*}"' \
  493. '--recompress=[recompress data chunks according to "MODE" and "--compression"]:MODE:'"(($mods))" \
  494. $common_options \
  495. ':REPOSITORY_OR_ARCHIVE: _borg_repository_or_archive' \
  496. '*: : _borg_style_selector_or_archive_files -e "$line[1]" pp'
  497. }
  498. (( $+functions[_borg-rename] )) ||
  499. _borg-rename() {
  500. local -a common_options
  501. __borg_setup_common_options
  502. _arguments -s -w -S : \
  503. $common_options \
  504. ':ARCHIVE: _borg_repository_or_archive -a' \
  505. ':NEWNAME'
  506. }
  507. (( $+functions[_borg-serve] )) ||
  508. _borg-serve() {
  509. local -a common_options common_init_options
  510. __borg_setup_common_options
  511. __borg_setup_common_init_options
  512. _arguments -s -w -S : \
  513. $common_init_options \
  514. '*--restrict-to-path=[restrict repository access to PATH]:PATH:_files' \
  515. '*--restrict-to-repository=[restrict repository access]: :_borg_repository'
  516. }
  517. (( $+functions[_borg-umount] )) ||
  518. _borg-umount() {
  519. local -a common_options
  520. __borg_setup_common_options
  521. _arguments -s -w -S : \
  522. $common_options \
  523. ':MOUNTPOINT:_umountable'
  524. }
  525. (( $+functions[_borg-upgrade] )) ||
  526. _borg-upgrade() {
  527. local -a common_options
  528. __borg_setup_common_options
  529. _arguments -s -w -S : \
  530. '(-n --dry-run)'{-n,--dry-run}'[do not change repository]' \
  531. '--inplace[rewrite repository in place, with no chance of going back to older versions of the repository]' \
  532. '--force[force upgrade]' \
  533. '--tam[enable manifest authentication (in key and cache)]' \
  534. '--disable-tam[disable manifest authentication (in key and cache)]' \
  535. $common_options \
  536. ':: :_borg_repository'
  537. }
  538. (( $+functions[_borg-with-lock] )) ||
  539. _borg-with-lock() {
  540. local -a state line common_options
  541. local curcontext="$curcontext" state_descr
  542. declare -A opt_args
  543. local -i ret=1
  544. __borg_setup_common_options
  545. _arguments -s -w -C -S : \
  546. $common_options \
  547. '(-): :_borg_repository' \
  548. '(-):COMMAND: _command_names -e' \
  549. '(-)*:ARGS:->normal' && ret=0
  550. case $state in
  551. (normal)
  552. shift 2 words
  553. (( CURRENT -= 2 ))
  554. _normal && ret=0
  555. ;;
  556. esac
  557. return ret
  558. }
  559. (( $+functions[__borg_setup_common_options] )) ||
  560. __borg_setup_common_options() {
  561. typeset -ga common_options=(
  562. '(- :)'{-h,--help}'[show this help message and exit]'
  563. '--critical[work on log level CRITICAL]'
  564. '--error[work on log level ERROR]'
  565. '--warning[work on log level WARNING (default)]'
  566. '(--info -v --verbose)'{--info,-v,--verbose}'[work on log level INFO]'
  567. '--debug[work on log level DEBUG]'
  568. '--debug-topic=[enable TOPIC debugging (can be specified multiple times)]:TOPIC'
  569. '(-p --progress)'{-p,--progress}'[show progress information]'
  570. '--log-json[Output one JSON object per log line instead of formatted text.]'
  571. '--lock-wait=[wait at most SECONDS for acquiring a repository/cache lock (default: 1)]: : _borg_guard_unsigned_number "SECONDS"'
  572. '--bypass-lock[bypass locking mechanism]'
  573. '(- :)--show-version[show/log the borg version]'
  574. '--show-rc[show/log the return code (rc)]'
  575. '--umask=[set umask to M (local and remote, default: 0077)]: : _borg_guard_numeric_mode "M"'
  576. '--remote-path=[set remote path to executable (default: "borg")]: :_cmdstring'
  577. '--remote-ratelimit=[set remote network upload rate limit in kiByte/s (default: 0=unlimited)]: : _borg_guard_unsigned_number "RATE"'
  578. '--consider-part-files[treat part files like normal files (e.g. to list/extract them)]'
  579. '--debug-profile=[write execution profile in Borg format into FILE]:FILE:_files'
  580. '--rsh=[use COMMAND instead of ssh]: :_cmdstring'
  581. )
  582. }
  583. (( $+functions[__borg_setup_common_exclude_options] )) ||
  584. __borg_setup_common_exclude_options() {
  585. typeset -ga common_exclude_options=(
  586. '*'{-e,--exclude}'=[exclude paths matching PATTERN]: : _borg_style_selector_or_archive_files "$line[1]" fm'
  587. '*--exclude-from=[read exclude patterns from EXCLUDEFILE, one per line]:EXCLUDEFILE:_files'
  588. '*--pattern=[experimental: include/exclude paths matching PATTERN]: : _borg_style_selector_or_archive_files -p "$line[1]" sh'
  589. '*--patterns-from=[experimental: read include/exclude patterns from PATTERNFILE, one per line]:PATTERNFILE:_files'
  590. )
  591. }
  592. (( $+functions[__borg_setup_common_exclude_extract_options] )) ||
  593. __borg_setup_common_exclude_extract_options() {
  594. local -a common_exclude_options
  595. __borg_setup_common_exclude_options
  596. typeset -ga common_exclude_extract_options=(
  597. $common_exclude_options
  598. '--strip-components=[Remove the specified number of leading path elements. Paths with fewer elements will be silently skipped.]: : _borg_guard_unsigned_number "NUMBER"'
  599. )
  600. }
  601. (( $+functions[__borg_setup_common_prefix_and_glob_archives_filter_options] )) ||
  602. __borg_setup_common_prefix_and_glob_archives_filter_options() {
  603. typeset -ga common_prefix_and_glob_archives_filter_options=(
  604. '(-P --prefix -a --glob-archives)'{-P,--prefix}'=[only consider archive names starting with this prefix]:PREFIX: _borg_archive -n "${line[1]%%\:\:*}"'
  605. '(-P --prefix)*'{-a,--glob-archives}'=[only consider archive names matching the glob]:GLOB: _borg_archive -n "${line[1]%%\:\:*}"'
  606. )
  607. }
  608. (( $+functions[__borg_setup_common_archive_filters_options] )) ||
  609. __borg_setup_common_archive_filters_options() {
  610. local -a common_prefix_and_glob_archives_filter_options
  611. __borg_setup_common_prefix_and_glob_archives_filter_options
  612. typeset -ga common_archive_filters_options=(
  613. $common_prefix_and_glob_archives_filter_options
  614. '--sort-by=[Comma-separated list of sorting keys, default: timestamp]:KEYS:(timestamp name id)'
  615. '(--last)--first=[consider first N archives after other filters were applied]:N: _borg_archive -n "${line[1]%%\:\:*}"'
  616. '(--first)--last=[consider last N archives after other filters were applied]:N: _borg_archive -n "${line[1]%%\:\:*}"'
  617. )
  618. }
  619. (( $+functions[__borg_setup_common_dry_run_stats_options] )) ||
  620. __borg_setup_common_dry_run_stats_options() {
  621. typeset -ga common_dry_run_stats_options=(
  622. '(-n --dry-run -s --stats)'{-n,--dry-run}'[do not change anything]'
  623. '(-n --dry-run -s --stats)'{-s,--stats}'[print statistics at end]'
  624. # NOTE: actual messages for subcommands differ in details
  625. )
  626. }
  627. (( $+functions[__borg_setup_common_create_options] )) ||
  628. __borg_setup_common_create_options() {
  629. local -a common_dry_run_stats_options common_exclude_options
  630. __borg_setup_common_dry_run_stats_options
  631. __borg_setup_common_exclude_options
  632. typeset -ga common_create_options=(
  633. $common_dry_run_stats_options
  634. '--list[output verbose list of items (files, dirs, ...)]'
  635. '--filter=[only display items with the given status characters]: :_borg_statuschars'
  636. $common_exclude_options
  637. '--exclude-caches[exclude directories that contain a CACHEDIR.TAG file]'
  638. '*--exclude-if-present=[exclude directories that are tagged by containing a filesystem object with the given NAME]:NAME:_files'
  639. '--keep-'{exclude-tags,tag-files}'[if tag objects are specified with --exclude-if-present, don'\''t omit the tag objects themselves]'
  640. '--comment=[add a comment text to the archive]:COMMENT:_borg_placeholders'
  641. '--timestamp=[manually specify the archive creation date/time]:TIMESTAMP:_borg_timestamp'
  642. '(-c --checkpoint-interval)'{-c,--checkpoint-interval}'=[write checkpoint every SECONDS seconds (default: 1800)]: : _borg_guard_unsigned_number "SECONDS"'
  643. '--chunker-params=[specify the chunker parameters]: :_borg_chunker_params'
  644. '(-C --compression)'{-C,--compression}'=[select compression algorithm]: :_borg_compression'
  645. )
  646. }
  647. (( $+functions[__borg_setup_common_init_options] )) ||
  648. __borg_setup_common_init_options() {
  649. local -a common_options
  650. __borg_setup_common_options
  651. typeset -ga common_init_options=(
  652. $common_options
  653. '--append-only[only allow appending to repository segment files]'
  654. '--storage-quota=[override storage quota of the repository]: :_borg_quota_suffixes'
  655. )
  656. }
  657. (( $+functions[_borgfs] )) ||
  658. _borgfs() {
  659. _borg-mount '(- :)'{-V,--version}'[show version number and exit]'
  660. }
  661. (( $+functions[_borg_parameters] )) ||
  662. _borg_parameters() {
  663. local name=$1
  664. shift
  665. local -i ret=1
  666. local -a expl
  667. case $name in
  668. (REPO)
  669. local BORG_REPO
  670. unset BORG_REPO
  671. _borg_repository && ret=0
  672. ;;
  673. ((|NEW_)PASSPHRASE)
  674. _message -e 'passphrase' && ret=0
  675. ;;
  676. (DISPLAY_PASSPHRASE)
  677. _message -e 'answer to the "display the passphrase for verification" question' && ret=0
  678. ;;
  679. (HOST_ID)
  680. _message -e 'unique ID' && ret=0
  681. ;;
  682. (FILES_CACHE_SUFFIX)
  683. _message -e 'suffix' && ret=0
  684. ;;
  685. (FILES_CACHE_TTL)
  686. _borg_guard_unsigned_number 'time to live (default: 20)' && ret=0
  687. ;;
  688. (MOUNT_DATA_CACHE_ENTRIES)
  689. _borg_guard_unsigned_number 'number of cached data chunks' && ret=0
  690. ;;
  691. (PASSCOMMAND|RSH|REMOTE_PATH)
  692. _cmdstring && ret=0
  693. ;;
  694. (HOSTNAME_IS_UNIQUE|SHOW_SYSINFO|(UNKNOWN_UNENCRYPTED|RELOCATED)_REPO_ACCESS_IS_OK)
  695. _description values expl 'value'
  696. compadd "$expl[@]" yes no && ret=0
  697. ;;
  698. ((CHECK|DELETE)_I_KNOW_WHAT_I_AM_DOING)
  699. _description values expl 'value'
  700. compadd "$expl[@]" YES NO && ret=0
  701. ;;
  702. (LIBC)
  703. _wanted libraries expl 'library' \
  704. compadd - ${^=LD_LIBRARY_PATH:-/usr/lib /usr/local/lib}/lib*.(a|so*)(:t) && ret=0
  705. ;;
  706. (SELFTEST)
  707. _description values expl 'value'
  708. compadd "$expl[@]" disabled && ret=0
  709. ;;
  710. (WORKAROUNDS)
  711. _wanted workarounds expl 'workaround' _sequence -n 1 compadd - basesyncfile && ret=0
  712. ;;
  713. (KEYS_DIR)
  714. _directories && ret=0
  715. ;;
  716. (*)
  717. _default && ret=0
  718. ;;
  719. esac
  720. return ret
  721. }
  722. (( $+functions[_borg_repository] )) ||
  723. _borg_repository() {
  724. local -a alts opts qopts
  725. zparseopts -E -a opts S:
  726. qopts=( ${(q)opts} )
  727. [[ -n $BORG_REPO ]] && alts+=( "default-repository: : __borg_default_repository $qopts" )
  728. alts+=( "cached-repositories:cached repositories:_borg_cached_repositories $qopts" )
  729. alts+=( 'directories: :_directories -r ":/ \t\n\-"' )
  730. alts+=( 'remote-repositories: : _borg_remote_repositories' )
  731. _alternative $alts
  732. }
  733. (( $+functions[__borg_default_repository] )) ||
  734. __borg_default_repository() {
  735. local -a opts suf
  736. zparseopts -E -a opts S:
  737. (( $opts[(I)-S] )) && suf=( -S '' )
  738. local -a default_repository=( "\:\::$BORG_REPO" )
  739. _describe -t default-repository 'default repository' default_repository "$suf[@]"
  740. }
  741. (( $+functions[_borg_cached_repositories] )) ||
  742. _borg_cached_repositories() {
  743. local -a cached_repos
  744. local sed_script='/^previous_location = / {
  745. s///
  746. # no port was given
  747. /ssh:\/\/[^/:]+:[0-9]+/! {
  748. # lstrip the `ssh://` prefix and add a colon before the first slash
  749. s!ssh://([^:/]+)/(.*)!\1:/\2!
  750. }
  751. p
  752. }'
  753. local cachedir=${BORG_CACHE_DIR:-${XDG_CACHE_HOME:-${BORG_BASE_DIR:-$HOME}/.cache}/borg}
  754. cached_repos=( ${(f)"$(_call_program -p cached-repositories sed -n -E ${(q)sed_script} \
  755. "${(q)cachedir}/*/config(#qN.om)" 2>/dev/null)"} )
  756. if [[ $compstate[quote] != (\'|\") ]]; then
  757. # hide ~BORG_REPO and other scalars
  758. local BORG_REPO
  759. unset BORG_REPO sed_script cachedir
  760. cached_repos=( "${(@D)cached_repos}" )
  761. fi
  762. compadd -Q "$@" -r ': \t\n\-' -a cached_repos
  763. }
  764. (( $+functions[_borg_remote_repositories] )) ||
  765. _borg_remote_repositories() {
  766. local -a match mbegin mend expl alts
  767. if compset -P '(#b)ssh://[^/]##@[^/]##:([0-9]##)/'; then
  768. _remote_files -/ -- ssh -p $match[1]
  769. return
  770. fi
  771. local -i have_scheme=0
  772. compset -P 'ssh://' && have_scheme=1
  773. if compset -P '*:'; then
  774. (( have_scheme )) && alts+=( 'ports: : _borg_guard_unsigned_number "port"' )
  775. alts+=( 'remote-files:remote file: _remote_files -/ -- ssh' )
  776. _alternative $alts
  777. elif compset -P 1 '(#b)(*)@'; then
  778. local user=$match[1]
  779. _wanted -C user-at hosts expl "host for $user" \
  780. _combination -s '[:@]' accounts users-hosts users="$user" hosts -S ':' -
  781. elif compset -S '@*'; then
  782. _wanted users expl "user" \
  783. _combination -s '[:@]' accounts users-hosts users -q -
  784. else
  785. alts=(
  786. 'users:user:_users -S "@"'
  787. 'hosts:host:_hosts -S ":"'
  788. )
  789. (( ! have_scheme )) && alts+=( 'prefixes:ssh:compadd -S "" ssh://' )
  790. _alternative $alts
  791. fi
  792. }
  793. # _borg_repository_or_archive [-a] [-p]
  794. #
  795. # -a archive is mandatory. The suffix `::` will be added to the repository if possible.
  796. # -p complete placeholders
  797. (( $+functions[_borg_repository_or_archive] )) ||
  798. _borg_repository_or_archive() {
  799. local -A opts
  800. zparseopts -A opts -D -E a p
  801. if compset -P 1 '*::'; then
  802. local qrepo=$IPREFIX[1,-3]
  803. local -i def_repo=0
  804. [[ -z $qrepo && -n $BORG_REPO ]] && qrepo=${(q)BORG_REPO} && def_repo=1
  805. if [[ -n $qrepo ]]; then
  806. if (( ! def_repo )); then
  807. case $compstate[quote] in
  808. (\') qrepo=${(qq)qrepo} ;;
  809. (\") qrepo=${(qqq)${(e)qrepo}} ;;
  810. # NOTE: currently `(e)` don't have any effect, but maybe one day zsh will stop to change the quoting method
  811. # of double quoted parameters
  812. esac
  813. fi
  814. if (( $+opts[-p] )); then
  815. _borg_placeholder_or_archive $qrepo
  816. else
  817. _borg_archive $qrepo
  818. fi
  819. else
  820. _message "not a borg repository: ${(Q)qrepo}"
  821. return 1
  822. fi
  823. else
  824. local -a suf
  825. if ! compset -S '::*'; then
  826. if (( $+opts[-a] )) || zstyle -T ":completion:${curcontext}:repositories" repository-suffix; then
  827. suf=( -S '::' )
  828. fi
  829. local oqrepo="$PREFIX$SUFFIX"
  830. local qrepo=$oqrepo
  831. [[ $compstate[quote] != (\'|\") ]] && qrepo=${(Q)qrepo}
  832. if __borg_is_borg_repo $qrepo; then
  833. qrepo=${oqrepo%%/}
  834. [[ -z $SUFFIX ]] && PREFIX=${PREFIX%%/} || SUFFIX=${SUFFIX%%/}
  835. compadd -S '::' -r ':/ \t\n\-' -Q -- $qrepo
  836. return
  837. fi
  838. fi
  839. _borg_repository "$suf[@]"
  840. fi
  841. }
  842. # _borg_archive [-F] [-n] [qrepo]
  843. #
  844. # -F don't apply archive filter options on the command line
  845. # -n reverse order, disable matchers and don't do menu completion/selection
  846. (( $+functions[_borg_archive] )) ||
  847. _borg_archive() {
  848. local -A opts
  849. zparseopts -A opts -D -E F n
  850. local qrepo=$1
  851. if [[ -z $qrepo ]]; then
  852. if [[ -n $BORG_REPO ]]; then
  853. qrepo=${(q)BORG_REPO}
  854. else
  855. _message 'no repository specified'
  856. return 1
  857. fi
  858. fi
  859. local -i ret=1
  860. _tags archives
  861. while _tags; do
  862. if _requested archives; then
  863. local -a expl disp archive_filters
  864. local -i reversed_order=1
  865. if (( ! $+opts[-F] )); then
  866. local -a archive_filter_options=( -P --prefix -a --glob-archives --first --last --sort-by ) tmp
  867. local k
  868. for k in $archive_filter_options; do
  869. if [[ -n $opt_args[$k] ]]; then
  870. IFS=: read -A tmp <<<$opt_args[$k]
  871. archive_filters+=( $k=${^tmp:#} )
  872. fi
  873. done
  874. fi
  875. if (( $+opts[-n] )); then
  876. __borg_skip_pattern_matching || return 1
  877. disp+=( -U )
  878. compstate[insert]=''
  879. compstate[list]='list force'
  880. reversed_order=0
  881. fi
  882. local -a asort
  883. zstyle -a ":completion:${curcontext}:archives" archive-sort asort
  884. if (( $asort[(I)inverse] )); then
  885. (( reversed_order = ! reversed_order ))
  886. fi
  887. local -a sort_by=( --sort-by=${(M)^asort:#(timestamp|name|id)} )
  888. # NOTE: in case of option repetition, the later one takes precedence
  889. if (( ! $+__borg_archives_need_update )); then
  890. comppostfuncs+=( __borg_unset_archives_need_update )
  891. typeset -gHi __borg_archives_need_update=1
  892. if (( ! $#archive_filters && ! $+opts[-n] )); then
  893. local erepo
  894. [[ -n $1 ]] && __borg_expand_path ${(Q)qrepo} erepo
  895. local -a newest_file=( $erepo/(hints|index|integrity).<1->(#qN.om[1]) )
  896. if [[ -n $newest_file ]]; then
  897. if zmodload -F zsh/stat b:zstat 2>/dev/null; then
  898. local -a stats
  899. zstat -A stats +mtime $newest_file
  900. local -i mtime=$stats[1]
  901. if [[ $__borg_prev_repo == $erepo
  902. && __borg_prev_mtime -ge mtime
  903. && $__borg_prev_order == $reversed_order
  904. && $__borg_prev_sort_by == $sort_by ]]
  905. then
  906. __borg_archives_need_update=0
  907. else
  908. typeset -gH __borg_prev_repo=$erepo
  909. typeset -gHi __borg_prev_mtime=mtime __borg_prev_order=reversed_order
  910. typeset -gHa __borg_prev_sort_by=( $sort_by )
  911. fi
  912. fi
  913. fi
  914. else
  915. unset __borg_prev_{repo,mtime,order,sort_by}
  916. comppostfuncs+=( __borg_unset_archives )
  917. fi
  918. fi
  919. if zstyle -t ":completion:${curcontext}:archives" verbose; then
  920. if (( __borg_archives_need_update || ! $+__borg_archive_names || ! $+__borg_archive_descriptions )); then
  921. __borg_archives_need_update=0
  922. typeset -gHa __borg_archive_names=() __borg_archive_descriptions=()
  923. local fmt descfmt name desc
  924. zstyle -s ":completion:${curcontext}:archives" archive-description-format descfmt ||
  925. descfmt='{archive:<36} {time} [{id}]'
  926. fmt="{barchive}{NUL}$descfmt{NUL}"
  927. _call_program -p archive-descriptions \
  928. ${(q)__borg_command:-borg} list --format=${(q)fmt} ${(q)sort_by} $archive_filters $qrepo 2>/dev/null |
  929. while IFS= read -r -d $'\0' name && IFS= read -r -d $'\0' descr; do
  930. __borg_archive_names[1,0]=( $name )
  931. __borg_archive_descriptions[1,0]=( "$descr" )
  932. done
  933. (( $pipestatus[1] )) && {
  934. _message "couldn't list repository: ${(Q)qrepo}"
  935. unset __borg_prev_{repo,mtime,order,sort_by}
  936. return 1
  937. }
  938. (( ! reversed_order )) &&
  939. __borg_archive_names=( "${(@aO)__borg_archive_names}" ) &&
  940. __borg_archive_descriptions=( "${(@aO)__borg_archive_descriptions}" )
  941. fi
  942. disp+=( -ld __borg_archive_descriptions )
  943. elif (( __borg_archives_need_update || ! $+__borg_archive_names )); then
  944. __borg_archives_need_update=0
  945. typeset -gHa __borg_archive_names=()
  946. local fmt='{barchive}{NUL}'
  947. __borg_archive_names=( ${(@0aO)"$(_call_program -p archives \
  948. ${(q)__borg_command:-borg} list --format=${(q)fmt} ${(q)sort_by} $archive_filters $qrepo 2>/dev/null)"} )
  949. (( $pipestatus[1] )) && {
  950. _message "couldn't list repository: ${(Q)qrepo}"
  951. unset __borg_prev_{repo,mtime,order,sort_by}
  952. return 1
  953. }
  954. (( ! reversed_order )) &&
  955. __borg_archive_names=( "${(@aO)__borg_archive_names}" )
  956. fi
  957. _all_labels archives expl 'ARCHIVE' compadd "$disp[@]" -a __borg_archive_names && ret=0
  958. fi
  959. (( ret )) || return 0
  960. done
  961. return 1
  962. }
  963. (( $+functions[__borg_unset_archives] )) ||
  964. __borg_unset_archives() {
  965. unset __borg_archive_names __borg_archive_descriptions
  966. }
  967. (( $+functions[__borg_unset_archives_need_update] )) ||
  968. __borg_unset_archives_need_update() {
  969. unset __borg_archives_need_update
  970. }
  971. (( $+functions[__borg_is_borg_repo] )) ||
  972. __borg_is_borg_repo() {
  973. local repo=$1
  974. __borg_expand_path $repo repo
  975. if [[ -d $repo && -d $repo/data ]]; then
  976. local -a files=( $repo/(hints|index|integrity).<1->(#qN.) )
  977. (( $#files >= 3 )) && return 0
  978. fi
  979. return 1
  980. }
  981. (( $+functions[__borg_expand_path] )) ||
  982. __borg_expand_path() {
  983. local _path=$1
  984. local -a match mbegin mend
  985. if [[ $_path == (#b)(\~[^/]#)(|/*) ]]; then
  986. local etilde
  987. etilde=$~match[1] 2>/dev/null
  988. _path="$etilde$match[2]"
  989. fi
  990. _path=${(e)_path//\\\\/\\\\\\\\}
  991. eval typeset -g ${2:-REPLY}=\$_path
  992. }
  993. (( $+functions[_borg_placeholder_or_archive] )) ||
  994. _borg_placeholder_or_archive() {
  995. local qrepo=$1
  996. shift
  997. _alternative \
  998. 'placeholders: :_borg_placeholders' \
  999. "archives: : _borg_archive ${(q)qrepo}"
  1000. }
  1001. (( $+functions[_borg_placeholders] )) ||
  1002. _borg_placeholders() {
  1003. local -a placeholders=(
  1004. 'hostname:The (short) hostname of the machine.'
  1005. 'fqdn:The full name of the machine.'
  1006. 'reverse-fqdn:The full name of the machine in reverse domain name notation.'
  1007. 'now:The current local date and time, by default in ISO-8601 format. You can also supply your own format string, e.g. {now:%Y-%m-%d_%H:%M:%S}'
  1008. 'utcnow:The current UTC date and time, by default in ISO-8601 format. You can also supply your own format string, e.g. {utcnow:%Y-%m-%d_%H:%M:%S}'
  1009. 'user:The user name (or UID, if no name is available) of the user running borg.'
  1010. 'pid:The current process ID.'
  1011. 'borgversion:The version of borg, e.g.: 1.0.8rc1'
  1012. 'borgmajor:The version of borg, only the major version, e.g.: 1'
  1013. 'borgminor:The version of borg, only major and minor version, e.g.: 1.0'
  1014. 'borgpatch:The version of borg, only major, minor and patch version, e.g.: 1.0.8'
  1015. )
  1016. __borg_complete_keys _describe -t placeholders 'placeholder' placeholders '"$copts[@]"'
  1017. }
  1018. (( $+functions[_borg_format_keys] )) ||
  1019. _borg_format_keys() {
  1020. local repo_or_arch=${(Q)1}
  1021. local -a keys=( NEWLINE NL NUL SPACE TAB CR LF )
  1022. local -a repository_keys=( archive name barchive comment bcomment id start time end command_line hostname username )
  1023. local -a archive_keys=( type mode uid gid user group path bpath source linktarget flags size csize dsize dcsize
  1024. num_chunks unique_chunks mtime ctime atime isomtime isoctime isoatime blake2b blake2s md5 sha1 sha224 sha256 sha384
  1025. sha3_224 sha3_256 sha3_384 sha3_512 sha512 shake_128 shake_256 archiveid archivename extra health )
  1026. local akeys rkeys
  1027. akeys='archive-keys:archive keys:compadd -a archive_keys'
  1028. rkeys='repository-keys:repository keys:compadd -a repository_keys'
  1029. local -a alts=( 'keys:keys:compadd -a keys' )
  1030. if [[ $repo_or_arch == *::?* ]]; then
  1031. alts+=( $akeys )
  1032. elif [[ -n $repo_or_arch ]]; then
  1033. alts+=( $rkeys )
  1034. else
  1035. alts+=( $rkeys $akeys )
  1036. fi
  1037. __borg_complete_keys _alternative -O copts ${(q)alts}
  1038. }
  1039. (( $+functions[__borg_complete_keys] )) ||
  1040. __borg_complete_keys() {
  1041. compset -P '*[^A-Za-z]##'
  1042. compset -S '[^A-Za-z]##*'
  1043. [[ -n $ISUFFIX ]] && compstate[to_end]=''
  1044. # NOTE: `[[ -n $ISUFFIX ]]` is a workaround for a bug that causes cursor movement to the right further than it should
  1045. # NOTE: the _oldlist completer doesn't respect compstate[to_end]=''
  1046. local ipref suf
  1047. if [[ $IPREFIX[-1] != '{' ]]; then
  1048. ipref='{'
  1049. [[ $compstate[quote] != (\'|\") ]] && ipref='\{'
  1050. fi
  1051. if [[ $ISUFFIX[1] != (|\\)\} ]]; then
  1052. suf='}'
  1053. [[ $compstate[quote] != (\'|\") ]] && suf='\}'
  1054. fi
  1055. local -a copts=( -i "$ipref" -S "$suf" )
  1056. eval "$@"
  1057. }
  1058. # _borg_style_selector_or_archive_files [-e] [-p] archive default_style_selector
  1059. #
  1060. # -e apply exclusion options on the command line
  1061. # -p complete `--pattern`
  1062. # -f complete files rather than borg paths
  1063. (( $+functions[_borg_style_selector_or_archive_files] )) ||
  1064. _borg_style_selector_or_archive_files() {
  1065. local -A opts
  1066. zparseopts -A opts -D -E e p f
  1067. local arch=$1 default_style_selector=$2
  1068. shift 2
  1069. local -a match mbegin mend expl tags=( style-selectors archive-files ) ss_suf=( -S ':' -r ':' )
  1070. (( $+opts[-f] )) && tags=( style-selectors files )
  1071. local -i ret=1
  1072. if (( $+opts[-p] )); then
  1073. if ! compset -P '(#b)([RP\+\-\!])'; then
  1074. local -a pattern_rules=(
  1075. 'P:pattern style'
  1076. 'R:root path'
  1077. '+:include'
  1078. '-:exclude'
  1079. '!:exclude non-recurse'
  1080. )
  1081. _describe -t pattern-rules 'pattern rule' pattern_rules -S ''
  1082. return
  1083. else
  1084. if [[ $compstate[quote] == (\'|\") ]]; then
  1085. compset -P ' #'
  1086. else
  1087. compset -P '(\\ )#'
  1088. fi
  1089. if [[ $match[1] == 'R' ]]; then
  1090. default_style_selector='pp'
  1091. elif [[ $match[1] == 'P' ]]; then
  1092. tags=( style-selectors )
  1093. ss_suf=()
  1094. fi
  1095. fi
  1096. fi
  1097. _tags $tags
  1098. while _tags; do
  1099. if _requested style-selectors; then
  1100. _all_labels style-selectors expl 'style selector' \
  1101. __borg_style_selectors $default_style_selector "$ss_suf[@]" - && ret=0
  1102. fi
  1103. if _requested archive-files; then
  1104. _all_labels archive-files expl 'PATTERN' \
  1105. __borg_archive_files ${(k)opts} "$arch" $default_style_selector - && ret=0
  1106. fi
  1107. if _requested files; then
  1108. local -a borg_paths=( ${(Q)${(e)${~@}}} )
  1109. _all_labels files expl 'PATH' \
  1110. __borg_pattern_files ${(k)opts} borg_paths - && ret=0
  1111. fi
  1112. (( ret )) || return 0
  1113. done
  1114. return 1
  1115. }
  1116. (( $+functions[__borg_style_selectors] )) ||
  1117. __borg_style_selectors() {
  1118. local default_style_selector=$1 path_style_selector
  1119. shift
  1120. zstyle -s ":completion:${curcontext}:archive-files" path-style-selector path_style_selector ||
  1121. path_style_selector='fm'
  1122. local -a disp
  1123. local -A style_selectors
  1124. __borg_setup_style_selectors
  1125. if zstyle -T ":completion:${curcontext}:style-selectors" verbose; then
  1126. local -a style_selector_descriptions extra
  1127. local k v sep
  1128. for k v in ${(kv)style_selectors}; do
  1129. extra=()
  1130. [[ $k == $default_style_selector ]] && extra+=( 'default' )
  1131. [[ $k == $path_style_selector ]] && __borg_choose_path_or_pattern "" "$default_style_selector" &&
  1132. extra+=( 'path' )
  1133. (( $#extra )) && v+=" (${(j:, :)extra})"
  1134. style_selector_descriptions+=( "${${k//\\/\\\\}//:/\\:}:$v" )
  1135. done
  1136. zstyle -s ":completion:${curcontext}:style-selectors" list-separator sep || sep=--
  1137. zformat -a style_selector_descriptions " $sep " $style_selector_descriptions
  1138. disp=( -ld style_selector_descriptions )
  1139. fi
  1140. compadd "$disp[@]" "$@" -k style_selectors
  1141. }
  1142. (( $+functions[__borg_archive_files] )) ||
  1143. __borg_archive_files() {
  1144. local -A opts
  1145. zparseopts -A opts -D e p
  1146. local arch=$1 default_style_selector=$2
  1147. shift 2
  1148. if [[ -z $arch || $arch != *::?* ]]; then
  1149. _message 'no archive specified'
  1150. return 1
  1151. fi
  1152. local -a qargs tmp disp pref match mbegin mend archive_files descs
  1153. local -A style_selectors
  1154. local k cword fmt descfmt style_selector path_style_selector name descr
  1155. # take into account exclude options on the command line
  1156. if (( $+opts[-e] )); then
  1157. local -a exclude_options=( -e --exclude --exclude-from --pattern --pattern-from )
  1158. local -a excludes
  1159. for k in $exclude_options; do
  1160. if [[ -n $opt_args[$k] ]]; then
  1161. IFS=: read -A tmp <<<$opt_args[$k]
  1162. excludes+=( $k="${^tmp[@]}" )
  1163. fi
  1164. done
  1165. [[ -n $excludes ]] && qargs+=( "$excludes[@]" )
  1166. fi
  1167. (( $_matcher_num > 1 )) && return 1
  1168. __borg_skip_pattern_matching || return 1
  1169. cword="$PREFIX$SUFFIX"
  1170. [[ $compstate[quote] != (\'|\") ]] && cword=${(Q)cword}
  1171. [[ -z $cword ]] && return 1
  1172. if zstyle -t ":completion:${curcontext}:archive-files" verbose; then
  1173. zstyle -s ":completion:${curcontext}:archive-files" file-description-format descfmt ||
  1174. descfmt='{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}'
  1175. fmt="{bpath}{NUL}$descfmt{NUL}"
  1176. else
  1177. fmt='{bpath}{NUL}'
  1178. fi
  1179. qargs+=( --format=${(q)fmt} )
  1180. qargs+=( $arch )
  1181. __borg_setup_style_selectors
  1182. [[ $cword == (#b)(${~${(j:|:)${(kb)style_selectors}}}):* ]] && style_selector=$match[1]
  1183. local -i path_expected=0
  1184. __borg_choose_path_or_pattern "$style_selector" $default_style_selector $cword && path_expected=1
  1185. if [[ -n $cword ]]; then
  1186. if (( path_expected )); then
  1187. [[ -n $style_selector ]] && compset -P "$style_selector:" && pref=( -P "$style_selector:" )
  1188. cword="$PREFIX$SUFFIX"
  1189. [[ $compstate[quote] != (\'|\") ]] && cword=${(Q)cword}
  1190. zstyle -s ":completion:${curcontext}:archive-files" path-style-selector path_style_selector ||
  1191. path_style_selector='fm'
  1192. cword="$path_style_selector:$cword"
  1193. else
  1194. [[ -z $style_selector ]] && cword="$default_style_selector:$cword"
  1195. fi
  1196. qargs+=( ${(q)cword} )
  1197. fi
  1198. if zstyle -t ":completion:${curcontext}:archive-files" verbose; then
  1199. _call_program -p archive-file-descriptions ${(q)__borg_command:-borg} list $qargs 2>/dev/null |
  1200. while IFS= read -r -d $'\0' name && IFS= read -r -d $'\0' descr; do
  1201. archive_files+=( $name )
  1202. descs+=( $descr )
  1203. done
  1204. (( $pipestatus[1] )) && { _message "couldn't list archive: ${(Q)arch}"; return 1 }
  1205. disp=( -ld descs )
  1206. else
  1207. archive_files=( ${(0)"$(_call_program -p archive-files ${(q)__borg_command:-borg} list $qargs 2>/dev/null)"} )
  1208. (( $pipestatus[1] )) && { _message "couldn't list archive: ${(Q)arch}"; return 1 }
  1209. fi
  1210. if (( $#archive_files )); then
  1211. if (( path_expected )); then
  1212. compstate[insert]='automenu'
  1213. else
  1214. compstate[insert]=''
  1215. compstate[list]='list force'
  1216. fi
  1217. fi
  1218. compadd "$pref[@]" -U "$disp[@]" "$@" -a archive_files
  1219. }
  1220. (( $+functions[__borg_choose_path_or_pattern] )) ||
  1221. __borg_choose_path_or_pattern() {
  1222. local ss=$1 defss=$2 cword=$3
  1223. shift 2
  1224. [[ $ss == (pp|pf) || ( -z $ss && $defss == (pp|pf) ) ]]
  1225. }
  1226. # transform borg exclude patterns into zsh ignore patterns and then complete files
  1227. (( $+functions[__borg_pattern_files] )) ||
  1228. __borg_pattern_files() {
  1229. local -A opts
  1230. zparseopts -A opts -D -E e p f
  1231. local paths_varname=$1
  1232. shift
  1233. local -a args
  1234. local -A style_selectors
  1235. __borg_setup_style_selectors
  1236. local pr_pat='[RP\+\-\!]' ss_pat="(${(j:|:)${(@kb)style_selectors}}):"
  1237. local prs_pat="$pr_pat #"
  1238. if (( $+opts[-e] )); then
  1239. local -a borg_excludes exclude_options=( -e --exclude --pattern ) tmp
  1240. local k cword
  1241. local -i i
  1242. for k in $exclude_options; do
  1243. if [[ -n $opt_args[$k] ]]; then
  1244. IFS=: read -A tmp <<<$opt_args[$k]
  1245. tmp=( ${(Q)tmp} )
  1246. # lstrip style selectors and pattern rules
  1247. [[ $+opts[-p] -gt 0 || $k == --pattern ]] && tmp=( ${tmp#$~prs_pat} )
  1248. tmp=( ${tmp#$~ss_pat} )
  1249. # don't take into account the word under the cursor
  1250. cword="$PREFIX$SUFFIX"
  1251. [[ $compstate[quote] != (\'|\") ]] && cword=${(Q)cword}
  1252. [[ $+opts[-p] -gt 0 || $k == --pattern ]] && cword=${cword#$~prs_pat}
  1253. cword=${cword#$~ss_pat}
  1254. i=$tmp[(I)$cword]
  1255. (( i )) && tmp=( "${(@)tmp[1,i-1]}" "${(@)tmp[i+1,-1]}" )
  1256. borg_excludes+=( "$tmp[@]" )
  1257. fi
  1258. done
  1259. [[ -n $borg_excludes ]] && args+=( -F borg_excludes )
  1260. fi
  1261. [[ -n ${(P)paths_varname} ]] && args+=( -W $paths_varname )
  1262. args+=( "$@" )
  1263. # lstrip style selectors and pattern rules
  1264. if (( $+opts[-p] )); then
  1265. if [[ $compstate[quote] != (\'|\") ]]; then
  1266. compset -P $pr_pat
  1267. compset -P '(\\ )#'
  1268. else
  1269. compset -P $prs_pat
  1270. fi
  1271. fi
  1272. compset -P $ss_pat
  1273. compstate[insert]=''
  1274. compstate[list]='list force'
  1275. _path_files "$args[@]"
  1276. }
  1277. (( $+functions[__borg_setup_style_selectors] )) ||
  1278. __borg_setup_style_selectors() {
  1279. typeset -gA style_selectors=(
  1280. fm 'Fnmatch'
  1281. sh 'Shell-style patterns'
  1282. re 'Regular expressions'
  1283. pp 'Path prefix'
  1284. pf 'Path full-match'
  1285. )
  1286. }
  1287. (( $+functions[__borg_skip_pattern_matching] )) ||
  1288. __borg_skip_pattern_matching() {
  1289. # unset glob_complete
  1290. [[ $compstate[pattern_match] == '*' ]] && compstate[pattern_match]=''
  1291. # skip the _match completer
  1292. [[ -n $compstate[pattern_match] ]] && return 1
  1293. return 0
  1294. }
  1295. (( $+functions[_borg_config] )) ||
  1296. _borg_config() {
  1297. local qrepo=$1
  1298. shift
  1299. if (( ! $+__borg_config_sect )); then
  1300. comppostfuncs+=( __borg_unset_config )
  1301. typeset -gH __borg_config_sect=
  1302. typeset -gHa __borg_config_keys=()
  1303. local sect line
  1304. local -a match mbegin mend
  1305. _call_program -p keys ${(q)__borg_command:-borg} config --list $qrepo 2>/dev/null | {
  1306. IFS= read -r sect
  1307. sect=${${sect#\[}%\]}
  1308. __borg_config_sect=$sect
  1309. while IFS= read -r line && [[ $line == (#b)(*)\ =\ (*) ]]; do
  1310. __borg_config_keys+=( "${${match[1]//\\/\\\\}//:/\\:}:(current: $match[2])" )
  1311. done
  1312. }
  1313. fi
  1314. local -a alts=( 'keys:key: _describe -t keys "key" __borg_config_keys' )
  1315. compset -P "${__borg_config_sect}." || alts+=( 'sections:section:compadd -S "." $__borg_config_sect' )
  1316. _alternative $alts
  1317. }
  1318. (( $+functions[__borg_unset_config] )) ||
  1319. __borg_unset_config() {
  1320. unset __borg_config_sect __borg_config_keys
  1321. }
  1322. # A simple prefix-oriented completion function for compressors. Can be improved by supporting the suffix.
  1323. (( $+functions[_borg_compression] )) ||
  1324. _borg_compression() {
  1325. local -a nolvl=(
  1326. 'none:do not compress'
  1327. 'lz4:very high speed, very low compression'
  1328. )
  1329. local -a havelvl=(
  1330. 'zstd:("zstandart")'
  1331. 'zlib:("gz") medium speed, medium compression'
  1332. 'lzma:("xz") low speed, high compression'
  1333. )
  1334. local -a auto=(
  1335. 'auto:compress compressible, otherwise "none"'
  1336. )
  1337. local -a match mbegin mend
  1338. # NOTE: Zsh's `-prefix` condition is confused by the leading parenthesis in the pattern.
  1339. # Fortunately, we simply need to show a message.
  1340. if compset -P '(#b)(|auto,)(zstd|zlib|lzma),'; then
  1341. local -i from to def
  1342. case $match[2] in
  1343. (zstd) from=1 to=22 def=3 ;;
  1344. (zlib|lzma) from=0 to=9 def=6 ;;
  1345. esac
  1346. _message -e "compression level (from $from to $to, default: $def)"
  1347. elif compset -P 'auto,'; then
  1348. _describe -t compression 'compression' nolvl -- havelvl -qS,
  1349. else
  1350. _describe -t compression 'compression' nolvl -- havelvl -qS, -- auto -S,
  1351. fi
  1352. }
  1353. (( $+functions[_borg_chunker_params] )) ||
  1354. _borg_chunker_params() {
  1355. if compset -P '*,*,*,'; then
  1356. _message -e 'HASH_WINDOW_SIZE'
  1357. elif compset -P '*,*,'; then
  1358. _message -e 'HASH_MASK_BITS (target chunk size ~= 2^HASH_MASK_BITS B)'
  1359. elif compset -P '*,'; then
  1360. _message -e 'CHUNK_MAX_EXP (maximum chunk size = 2^CHUNK_MAX_EXP B)'
  1361. else
  1362. _message -e 'CHUNK_MIN_EXP (minimum chunk size = 2^CHUNK_MIN_EXP B)'
  1363. local -a params=(
  1364. 'default:19,23,21,4095'
  1365. '19,23,21,4095:small amount of chunks (default)'
  1366. '10,23,16,4095:big amount of chunks'
  1367. )
  1368. _describe -t chunker-params 'typical chunker params' params
  1369. fi
  1370. }
  1371. (( $+functions[_borg_statuschars] )) ||
  1372. _borg_statuschars() {
  1373. _values -s '' 'STATUSCHARS' \
  1374. 'A[regular file, added]' \
  1375. 'M[regular file, modified]' \
  1376. 'U[regular file, unchanged]' \
  1377. 'E[regular file, an error happened while accessing/reading this file]' \
  1378. 'd[directory]' \
  1379. 'b[block device]' \
  1380. 'c[char device]' \
  1381. 'h[regular file, hardlink (to already seen inodes)]' \
  1382. 's[symlink]' \
  1383. 'f[fifo]' \
  1384. 'i[backup data was read from standard input (stdin)]' \
  1385. '-[dry run, item was not backed up]' \
  1386. 'x[excluded, item was not backed up]' \
  1387. '?[missing status code]'
  1388. }
  1389. (( $+functions[_borg_quota_suffixes] )) ||
  1390. _borg_quota_suffixes() {
  1391. if compset -P '[0-9]##'; then
  1392. local -a suffixes=(
  1393. 'K:10 ** 3 bytes'
  1394. 'M:10 ** 6 bytes'
  1395. 'G:10 ** 9 bytes'
  1396. 'T:10 ** 12 bytes'
  1397. 'P:10 ** 15 bytes'
  1398. )
  1399. # NOTE: tag `suffixes` is already in use (file extensions)
  1400. _describe -t multiplier 'suffix' suffixes
  1401. else
  1402. _message -e 'QUOTA'
  1403. fi
  1404. }
  1405. (( $+functions[_borg_timestamp] )) ||
  1406. _borg_timestamp() {
  1407. _alternative \
  1408. "dates:TIMESTAMP: _dates -f '%FT%T'" \
  1409. 'files:reference:_files'
  1410. }
  1411. (( $+functions[_borg_guard_unsigned_number] )) ||
  1412. _borg_guard_unsigned_number() {
  1413. local -A opts
  1414. zparseopts -K -D -A opts M+: J+: V+: 1 2 o+: n F: x+: X+:
  1415. _guard '[0-9]#' ${1:-number}
  1416. }
  1417. (( $+functions[_borg_guard_numeric_mode] )) ||
  1418. _borg_guard_numeric_mode() {
  1419. local -A opts
  1420. zparseopts -K -D -A opts M+: J+: V+: 1 2 o+: n F: x+: X+:
  1421. _guard '[0-7](#c0,4)' ${1:-mode}
  1422. }
  1423. _borg() {
  1424. local -a match mbegin mend line state
  1425. local curcontext="$curcontext" state_descr
  1426. typeset -A opt_args
  1427. local -i ret=1
  1428. if [[ $service == 'borg' ]]; then
  1429. local __borg_command=$words[1]
  1430. local -a common_options
  1431. __borg_setup_common_options
  1432. _arguments -s -w -C : \
  1433. '(- :)'{-V,--version}'[show version number and exit]' \
  1434. $common_options \
  1435. '(-): :->command' \
  1436. '(-)*:: :->option-or-argument' && return
  1437. case $state in
  1438. (command)
  1439. _borg_commands && ret=0
  1440. ;;
  1441. (option-or-argument)
  1442. curcontext="${curcontext%:*:*}:borg-$words[1]:"
  1443. if ! _call_function ret _borg-$words[1]; then
  1444. _default && ret=0
  1445. fi
  1446. ;;
  1447. esac
  1448. elif [[ $service == (#b)-value-,BORG_(*),-default- ]]; then
  1449. _borg_parameters $match[1] && ret=0
  1450. elif ! _call_function ret _$service; then
  1451. _default && ret=0
  1452. fi
  1453. return ret
  1454. }
  1455. _borg "$@"