_borg 52 KB

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