423 lines
20 KiB
Plaintext
423 lines
20 KiB
Plaintext
|
#compdef rmlint rmlint.sh -P rmlint.*.sh
|
||
|
|
||
|
# Copyright (c) 2021 Github zsh-users - http://github.com/zsh-users
|
||
|
#
|
||
|
# Permission is hereby granted, without written agreement and without
|
||
|
# licence or royalty fees, to use, copy, modify, and distribute this
|
||
|
# software and to distribute modified versions of this software for any
|
||
|
# purpose, provided that the above copyright notice and the following
|
||
|
# two paragraphs appear in all copies of this software.
|
||
|
#
|
||
|
# In no event shall the Zsh Development Group be liable to any party for
|
||
|
# direct, indirect, special, incidental, or consequential damages arising out
|
||
|
# of the use of this software and its documentation, even if the Zsh
|
||
|
# Development Group have been advised of the possibility of such damage.
|
||
|
#
|
||
|
# The Zsh Development Group specifically disclaim any warranties, including,
|
||
|
# but not limited to, the implied warranties of merchantability and fitness
|
||
|
# for a particular purpose. The software provided hereunder is on an "as is"
|
||
|
# basis, and the Zsh Development Group have no obligation to provide
|
||
|
# maintenance, support, updates, enhancements, or modifications.
|
||
|
#
|
||
|
# Description
|
||
|
# -----------
|
||
|
#
|
||
|
# Zsh completion for rmlint 2.10.1 (https://github.com/sahib/rmlint)
|
||
|
#
|
||
|
# Authors
|
||
|
# -------
|
||
|
#
|
||
|
# * oxiedi (https://github.com/oxiedi)
|
||
|
|
||
|
(( $+functions[_rmlint_types] )) ||
|
||
|
_rmlint_types() {
|
||
|
compset -P '*[+-]'
|
||
|
# FIXME: all values before `-` are swallowed by `*`, which breaks deduplication of the swallowed values
|
||
|
# TODO: respect `prefix-needed`
|
||
|
_values -s ',' 'list [defaults]' \
|
||
|
'all[enables all lint types]' \
|
||
|
'defaults[enables all lint types, but nonstripped]' \
|
||
|
'minimal[defaults minus emptyfiles and emptydirs]' \
|
||
|
'minimaldirs[defaults minus emptyfiles, emptydirs and duplicates, but with duplicatedirs]' \
|
||
|
'none[disable all lint types]' \
|
||
|
'(badids bi)'{badids,bi}'[find files with bad UID, GID or both]' \
|
||
|
'(badlinks bl)'{badlinks,bl}'[find bad symlinks pointing nowhere valid]' \
|
||
|
'(emptydirs ed)'{emptydirs,ed}'[find empty directories]' \
|
||
|
'(emptyfiles ef)'{emptyfiles,ef}'[find empty files]' \
|
||
|
'(nonstripped ns)'{nonstripped,ns}'[find nonstripped binaries]' \
|
||
|
'(duplicates df)'{duplicates,df}'[find duplicate files]' \
|
||
|
'(duplicatedirs dd)'{duplicatedirs,dd}'[find duplicate directories (This is the same -D!)]'
|
||
|
}
|
||
|
|
||
|
(( $+functions[__rmlint_setup_formatter_descriptions] )) ||
|
||
|
__rmlint_setup_formatter_descriptions() {
|
||
|
typeset -gA formatter_descriptions=(
|
||
|
csv 'output all found lint as comma-separated-value list'
|
||
|
sh 'output all found lint as shell script'
|
||
|
json 'print a JSON-formatted dump of all found reports'
|
||
|
py 'outputs a python script and a JSON document, just like the json formatter'
|
||
|
uniques 'outputs all unique paths found during the run, one path per line'
|
||
|
stamp 'outputs a timestamp of the time rmlint was run'
|
||
|
progressbar 'shows a progressbar'
|
||
|
pretty 'shows all found items in realtime nicely colored'
|
||
|
summary 'shows counts of files and their respective size after the run. Also list all written output files'
|
||
|
fdupes 'prints an output similar to the popular duplicate finder fdupes(1)'
|
||
|
)
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_output] )) ||
|
||
|
_rmlint_output() {
|
||
|
local -A formatter_descriptions
|
||
|
__rmlint_setup_formatter_descriptions
|
||
|
if compset -P "(${(kj:|:)formatter_descriptions}):"; then
|
||
|
_alternative \
|
||
|
'files:file:_files' \
|
||
|
'outputs:output:(stdout stderr)'
|
||
|
else
|
||
|
local -a outputs
|
||
|
local f d
|
||
|
for f d in ${(kv)formatter_descriptions}; do
|
||
|
outputs+=( "$f:$d" )
|
||
|
done
|
||
|
_describe -t outputs 'output' outputs -S ':' -q
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_config] )) ||
|
||
|
_rmlint_config() {
|
||
|
local -A formatter_descriptions
|
||
|
__rmlint_setup_formatter_descriptions
|
||
|
unset 'formatter_descriptions['{py,pretty,summary}']'
|
||
|
local -a match mbegin mend
|
||
|
if compset -P "(#b)(${(kj:|:)formatter_descriptions}):"; then
|
||
|
case $match[1] in
|
||
|
(csv)
|
||
|
_values 'option' \
|
||
|
'no_header[do not write a first line describing the column headers]' \
|
||
|
'unique[include unique files in the output]'
|
||
|
;;
|
||
|
(sh)
|
||
|
local context state state_descr line
|
||
|
_values 'option' \
|
||
|
'cmd[specify a user defined command to run on duplicates]: :_cmdstring' \
|
||
|
'handler[define a comma separated list of handlers to try on duplicate files in that given order until one handler succeeds]:handler:->handler' \
|
||
|
'link[shortcut for -c sh:handler=clone,reflink,hardlink,symlink]' \
|
||
|
'hardlink[shortcut for -c sh:handler=hardlink,symlink]' \
|
||
|
'symlink[shortcut for -c sh:handler=symlink]'
|
||
|
case $state in
|
||
|
(handler)
|
||
|
_values -s ',' $state_descr \
|
||
|
'clone[try to clone both files with the FIDEDUPERANGE ioctl(3p) (or BTRFS_IOC_FILE_EXTENT_SAME on older kernels)]' \
|
||
|
'reflink[try to reflink the duplicate file to the original]' \
|
||
|
'hardlink[replace the duplicate file with a hardlink to the original file]' \
|
||
|
'symlink[tries to replace the duplicate file with a symbolic link to the original]' \
|
||
|
'remove[remove the file using rm -rf]' \
|
||
|
'usercmd[use the provided user defined command (-c sh:cmd=something)]'
|
||
|
;;
|
||
|
esac
|
||
|
;;
|
||
|
(json)
|
||
|
_values 'option' \
|
||
|
'unique[include unique files in the output]' \
|
||
|
'no_header[print the header with metadata]:boolean [true]:(false true)' \
|
||
|
'no_footer[print the footer with statistics]:boolean [true]:(false true)' \
|
||
|
'oneline[print one json document per line]:boolean [false]:(true false)'
|
||
|
;;
|
||
|
(uniques)
|
||
|
_values 'option' \
|
||
|
'print0[do not put newlines between paths but zero bytes]'
|
||
|
;;
|
||
|
(stamp)
|
||
|
_values 'option' \
|
||
|
'iso8601[write an ISO8601 formatted timestamps or seconds since epoch]:boolean:(true false)'
|
||
|
;;
|
||
|
(progressbar)
|
||
|
_values 'option' \
|
||
|
'update_interval[number of milliseconds to wait between updates (default: 50)]: :_guard "[0-9]#" "update interval (milliseconds) [50]"' \
|
||
|
'ascii[do not attempt to use unicode characters, which might not be supported by some terminals]' \
|
||
|
'fancy[use a more fancy style for the progressbar]'
|
||
|
;;
|
||
|
(fdupes)
|
||
|
_values 'option' \
|
||
|
'omitfirst[omits the first line of each set of duplicates]' \
|
||
|
'sameline[does not print newlines between files, only a space]'
|
||
|
;;
|
||
|
esac
|
||
|
else
|
||
|
local -a formatters
|
||
|
local f d
|
||
|
for f d in ${(kv)formatter_descriptions}; do
|
||
|
formatters+=( "$f:$d" )
|
||
|
done
|
||
|
_describe -t formatters 'formatter' formatters -S ':'
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_algorithm] )) ||
|
||
|
_rmlint_algorithm() {
|
||
|
local -a tmp=( sha{1,256,512} sha3-{256,384,512} blake{2s,2b,2sp,2bp} highway{64,128,256} )
|
||
|
_alternative \
|
||
|
'512bit-algorithms:512-bit:(blake2b blake2bp sha3-512 sha512)' \
|
||
|
'384bit-algorithms:384-bit:(sha3-384)' \
|
||
|
'256bit-algorithms:256-bit:(blake2s blake2sp sha3-256 sha256 highway256 metro256 metrocrc256)' \
|
||
|
'160bit-algorithms:160-bit:(sha1)' \
|
||
|
'128bit-algorithms:128-bit:(md5 murmur metro metrocrc)' \
|
||
|
'64bit-algorithms:64-bit:(highway64 xxhash)' \
|
||
|
"cryptographic-algorithms:cryptographic:($tmp)" \
|
||
|
'non-cryptographic-algorithms:non-cryptographic:(metro metro256 xxhash murmur)' \
|
||
|
'not-useful-algorithms:not-useful:(cumulative paranoid ext)'
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_sort] )) ||
|
||
|
_rmlint_sort() {
|
||
|
local -A letter_descriptions=(
|
||
|
s 'sort by size of group'
|
||
|
a 'sort alphabetically by the basename of the original'
|
||
|
m 'sort by mtime of the original'
|
||
|
p 'sort by path-index of the original'
|
||
|
o 'sort by natural found order (might be different on each run)'
|
||
|
n 'sort by number of files in the group'
|
||
|
)
|
||
|
local -a letters
|
||
|
local l d
|
||
|
for l d in ${(kv)letter_descriptions}; do
|
||
|
letters+=( "${l}[$d]" "${(U)l}[$d (in reverse order)]" )
|
||
|
done
|
||
|
_values -s '' 'order' $letters
|
||
|
}
|
||
|
|
||
|
(( $+functions[__rmlint_describe_multipliers] )) ||
|
||
|
__rmlint_describe_multipliers() {
|
||
|
local -a multipliers=(
|
||
|
'C:1^1'
|
||
|
'W:2^1'
|
||
|
'B:512^1'
|
||
|
'K:1000^1'
|
||
|
'KB:1024^1'
|
||
|
'M:1000^2'
|
||
|
'MB:1024^2'
|
||
|
'G:1000^3'
|
||
|
'GB:1024^3'
|
||
|
'T:1000^4'
|
||
|
'TB:1024^4'
|
||
|
'P:1000^5'
|
||
|
'PB:1024^5'
|
||
|
'E:1000^6'
|
||
|
'EB:1024^6'
|
||
|
)
|
||
|
_describe -t multiplier 'multiplier' multipliers "$@"
|
||
|
}
|
||
|
|
||
|
(( $+functions[__rmlint_multipliers] )) ||
|
||
|
__rmlint_multipliers() {
|
||
|
compset -P '[0-9]##' || return
|
||
|
__rmlint_describe_multipliers "$@"
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_size] )) ||
|
||
|
_rmlint_size() {
|
||
|
! __rmlint_multipliers && [[ -z $PREFIX ]] && _message -e "${1:-size}"
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_size_range] )) ||
|
||
|
_rmlint_size_range() {
|
||
|
if compset -P '[0-9]##'; then
|
||
|
if compset -P '(C|W|B|K|KB|M|MB|G|GB|T|TB|P|PB|E|EB)-'; then
|
||
|
_rmlint_size 'max'
|
||
|
else
|
||
|
__rmlint_describe_multipliers -S '-' -q
|
||
|
fi
|
||
|
elif [[ -z $PREFIX ]]; then
|
||
|
_message -e 'min'
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_iso8601_or_unix_timestamp] )) ||
|
||
|
_rmlint_iso8601_or_unix_timestamp() {
|
||
|
_alternative \
|
||
|
'dates:iso8601_timestamp: _dates -f "%FT%T"' \
|
||
|
'seconds:unix_timestamp:_guard "[0-9]#" "seconds since epoch"'
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_rank] )) ||
|
||
|
_rmlint_rank() {
|
||
|
# TODO: {r,R,x,X}<regex>
|
||
|
_values -s '' 'criteria [pOma]' \
|
||
|
'm[keep lowest mtime (oldest)]' 'M[keep highest mtime (newest)]' \
|
||
|
'a[keep first alphabetically]' 'A[keep last alphabetically]' \
|
||
|
'p[keep first named path]' 'P[keep last named path]' \
|
||
|
'd[keep path with lowest depth]' 'D[keep path with highest depth]' \
|
||
|
'l[keep path with shortest basename]' 'L[keep path with longest basename]' \
|
||
|
'r[keep paths matching regex]' 'R[keep path not matching regex]' \
|
||
|
'x[keep basenames matching regex]' 'X[keep basenames not matching regex]' \
|
||
|
'h[keep file with lowest hardlink count]' 'H[keep file with highest hardlink count]' \
|
||
|
'o[keep file with lowest number of hardlinks outside of the paths traversed by rmlint]' \
|
||
|
'O[keep file with highest number of hardlinks outside of the paths traversed by rmlint]'
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_percent] )) ||
|
||
|
_rmlint_percent() {
|
||
|
if compset -P '(100|[1-9][0-9]|[1-9])'; then
|
||
|
compadd "$@" -- '%'
|
||
|
elif [[ -z $PREFIX ]]; then
|
||
|
_message -e 'percent%%'
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_clamp] )) ||
|
||
|
_rmlint_clamp() {
|
||
|
_alternative \
|
||
|
"factor: :_guard '((|0)(|.[0-9]#)|1(|.0#))' 'fac.tor [$1]'" \
|
||
|
'percent:percent%%:_rmlint_percent' \
|
||
|
'multiplier:offset: _rmlint_size "offset"'
|
||
|
}
|
||
|
|
||
|
(( $+functions[_rmlint_files_or_separator] )) ||
|
||
|
_rmlint_files_or_separator() {
|
||
|
if (( $words[(i)-] < CURRENT )); then
|
||
|
[[ -z $words[CURRENT] ]] && compadd "$@" -S '' -- -
|
||
|
return
|
||
|
fi
|
||
|
local -a alts=( 'files:file:_files' )
|
||
|
(( $line[(I)//] || $+opt_args[--equal] )) || alts+=( 'separator:separator:(//)' )
|
||
|
_alternative $alts
|
||
|
}
|
||
|
|
||
|
_rmlint() {
|
||
|
if [[ $service = *.sh ]]; then
|
||
|
_arguments -s : \
|
||
|
'(-)-h[show help message]' \
|
||
|
'-d[do not ask before running]' \
|
||
|
'-x[keep rmlint.sh; do not autodelete it]' \
|
||
|
'-p[recheck that files are still identical before removing duplicates]' \
|
||
|
'-r[allow deduplication of files on read-only btrfs snapshots (requires sudo)]' \
|
||
|
'(-d -x)-n[do not perform any modifications, just print what would be done (implies -d and -x)]' \
|
||
|
'-c[clean up empty directories while deleting duplicates]' \
|
||
|
'-q[do not show progress]' \
|
||
|
'-k[keep the timestamp of directories when removing duplicates]' \
|
||
|
'-i[ask before deleting each file]'
|
||
|
return
|
||
|
fi
|
||
|
|
||
|
local curcontext="$curcontext" state state_descr
|
||
|
local -a line
|
||
|
local -i ret=1
|
||
|
typeset -A opt_args
|
||
|
|
||
|
_arguments -s -w -C : \
|
||
|
'(-T --types)'{-T,--types}'=[configure the types of lint rmlint will look for]: :_rmlint_types' \
|
||
|
'*'{-o,--output}'=[configure the way rmlint outputs its results]:spec:_rmlint_output' \
|
||
|
'*'{-O,--add-output}'=[configure the way rmlint outputs its results (preserve defaults)]:spec:_rmlint_output' \
|
||
|
'*'{-c,--config}'=[configure a format]:spec:_rmlint_config' \
|
||
|
'(-z --perms)'{-z,--perms}'=[only look into file if it is readable, writable or executable by the current user]: :_values -s "" perms r w x' \
|
||
|
'(-a --algorithm)'{-a,--algorithm}'=[choose the algorithm to use for finding duplicate files]:algo:_rmlint_algorithm' \
|
||
|
'*'{-p,--paranoid}'[increase the paranoia of rmlint'\''s duplicate algorithm]' \
|
||
|
'*'{-P,--less-paranoid}'[decrease the paranoia of rmlint'\''s duplicate algorithm]' \
|
||
|
'*'{-v,--loud}'[increase the verbosity]' \
|
||
|
'*'{-V,--quiet}'[decrease the verbosity]' \
|
||
|
'(-g --progress)'{-g,--progress}'[show a progressbar with sane defaults]' \
|
||
|
'(-G --no-progress)'{-G,--no-progress}'[do not show a progressbar with sane defaults (default)]' \
|
||
|
'(-D --merge-directories)'{-D,--merge-directories}'[makes rmlint use a special mode where all found duplicates are collected and checked if whole directory trees are duplicates]' \
|
||
|
'(-j --honour-dir-layout)'{-j,--honour-dir-layout}'[only recognize directories as duplicates that have the same path layout]' \
|
||
|
'(-y --sort-by)'{-y,--sort-by}'=[during output, sort the found duplicate groups by criteria described by order]:order:_rmlint_sort' \
|
||
|
'(-w --with-color)'{-w,--with-color}'[use color escapes for pretty output (default)]' \
|
||
|
'(-W --no-with-color)'{-W,--no-with-color}'[disable color escapes for pretty output]' \
|
||
|
'(- *)'{-h,--help}'[show a shorter reference help text]' \
|
||
|
'(- *)--help-all[show all help options]' \
|
||
|
'(- *)'{-H,--show-man}'[show the full man page]' \
|
||
|
'(- *)--version[print the version of rmlint]' \
|
||
|
'(-s --size)'{-s,--size}'=[only consider files as duplicates in a certain size range]:range:_rmlint_size_range' \
|
||
|
'(-d --max-depth)'{-d,--max-depth}'=[only recurse up to this depth]: :_guard "[0-9]#" "depth"' \
|
||
|
'(-l --hardlinked)'{-l,--hardlinked}'[hardlinked files are treated as duplicates (default)]' \
|
||
|
'--keep-hardlinked[rmlint will not delete any files that are hardlinked to an original in their respective group]' \
|
||
|
'(-L --no-hardlinked)'{-L,--no-hardlinked}'[only one file (of a set of hardlinked files) is considered, all the others are ignored]' \
|
||
|
'(-f --followlinks)'{-f,--followlinks}'[follow symbolic links]' \
|
||
|
'(-F --no-followlinks)'{-F,--no-followlinks}'[ignore symbolic links completely]' \
|
||
|
'(-@ --see-symlinks)'{-@,--see-symlinks}'[see symlinks and treats them like small files with the path to their target in them (default)]' \
|
||
|
'(-x --no-crossdev)'{-x,--no-crossdev}'[stay always on the same device]' \
|
||
|
'(-X --crossdev)'{-X,--crossdev}'[allow crossing mountpoints (default)]' \
|
||
|
'(-r --hidden)'{-r,--hidden}'[traverse hidden directories]' \
|
||
|
'(-R --no-hidden)'{-R,--no-hidden}'[don'\''t traverse hidden directories (default)]' \
|
||
|
'--partial-hidden[traverse duplicate hidden directories]' \
|
||
|
'(-b --match-basename)'{-b,--match-basename}'[only consider those files as dupes that have the same basename]' \
|
||
|
'(-B --unmatched-basename)'{-B,--unmatched-basename}'[only consider those files as dupes that do not share the same basename]' \
|
||
|
'(-e --match-with-extension)'{-e,--match-with-extension}'[only consider those files as dupes that have the same file extension]' \
|
||
|
'(-E --no-match-with-extension)'{-E,--no-match-with-extension}'[don'\'t' consider those files as dupes that have the same file extension (default)]' \
|
||
|
'(-i --match-without-extension)'{-i,--match-without-extension}'[only consider those files as dupes that have the same basename minus the file extension]' \
|
||
|
'(-I --no-match-without-extension)'{-I,--no-match-without-extension}'[don'\'t' consider those files as dupes that have the same basename minus the file extension (default)]' \
|
||
|
'(-n --newer-than-stamp)'{-n,--newer-than-stamp}'=[only consider files (and their size siblings for duplicates) newer than a certain modification time (mtime)]:timestamp_filename:_files' \
|
||
|
'(-N --newer-than)'{-N,--newer-than}'=[don'\'t' consider files (and their size siblings for duplicates) newer than a certain modification time (mtime)]: :_rmlint_iso8601_or_unix_timestamp' \
|
||
|
'(-k --keep-all-tagged)'{-k,--keep-all-tagged}'[don'\''t delete any duplicates that are in tagged paths]' \
|
||
|
'(-K --keep-all-untagged)'{-K,--keep-all-untagged}'[don'\''t delete any duplicates that are in non-tagged paths]' \
|
||
|
'(-m --must-match-tagged)'{-m,--must-match-tagged}'[only look for duplicates of which at least one is in one of the tagged paths]' \
|
||
|
'(-M --must-match-untagged)'{-M,--must-match-untagged}'[only look for duplicates of which at least one is in one of the non-tagged paths]' \
|
||
|
'(-S --rank-by)'{-S,--rank-by}'=[sort the files in a group of duplicates into originals and duplicates by one or more criteria]: :_rmlint_rank' \
|
||
|
'--replay[read an existing json file and re-output it]' \
|
||
|
'(-C --xattr)'{-C,--xattr}'[shortcut for --xattr-read, --xattr-write, --write-unfinished]' \
|
||
|
'--xattr-read[read cached checksums from the extended file attributes]' \
|
||
|
'--xattr-write[write cached checksums from the extended file attributes]' \
|
||
|
'--xattr-clear[clear cached checksums from the extended file attributes]' \
|
||
|
'(-U --write-unfinished)'{-U,--write-unfinished}'[include files in output that have not been hashed fully, i.e. files that do not appear to have a duplicate]' \
|
||
|
'(-t --threads)'{-t,--threads}'=[the number of threads to use during file tree traversal and hashing (default: 16)]: :_guard "[0-9]#" "threads [16]"' \
|
||
|
'(-u --limit-mem)'{-u,--limit-mem}'=[apply a maximum number of memory to use for hashing and --paranoid]:size: _rmlint_size' \
|
||
|
'(-q --clamp-low)'{-q,--clamp-low}'=[only look at the content of files in the range of from low to (including) high (default: 0)]: : _rmlint_clamp 0' \
|
||
|
'(-Q --clamp-top)'{-Q,--clamp-top}'=[only look at the content of files in the range of from low to (including) high (default: 1.0)]: : _rmlint_clamp 1.0' \
|
||
|
'(-Z --mtime-window)'{-Z,--mtime-window}'=[only consider those files as duplicates that have the same content and the same modification time (mtime) within a certain window of T seconds (default: -1)]: :_guard "[0-9]#" "mtime window (seconds) [-1]"' \
|
||
|
'--with-fiemap[enable reading the file extents on rotational disk in order to optimize disk access patterns (default)]' \
|
||
|
'--without-fiemap[disable reading the file extents on rotational disk in order to optimize disk access patterns]' \
|
||
|
'--gui[start the optional graphical frontend to rmlint called Shredder]:*: :->gui' \
|
||
|
'--hash[make rmlint work as a multi-threaded file hash utility]:*: :->hash' \
|
||
|
'--equal[check if the paths given on the commandline all have equal content]: :_rmlint_files_or_separator' \
|
||
|
'(-0 --stdin0)'{-0,--stdin0}'[read null-separated file list from stdin]' \
|
||
|
'--backup[do create backups of previous result files]' \
|
||
|
'--no-backup[do not create backups of previous result files]' \
|
||
|
'--dedupe[dedupe matching extents from source to dest (if filesystem supports)]:*:: := ->dedupe' \
|
||
|
'--dedupe-xattr[check extended attributes to see if the file is already deduplicated]' \
|
||
|
'--dedupe-readonly[(--dedupe option) even dedupe read-only snapshots (needs root)]' \
|
||
|
'--is-reflink[test if two files are reflinks (share same data extents)]:*:: := ->reflink' \
|
||
|
'*: :_rmlint_files_or_separator' && return
|
||
|
|
||
|
case $state in
|
||
|
(gui)
|
||
|
_arguments -s -w : \
|
||
|
'(- *)'{-h,--help}'[show help options]' \
|
||
|
{-a,--add-location}'[add locations to locations view]' \
|
||
|
{-s,--scan}'[add location to scan (as untagged path)]' \
|
||
|
{-S,--scan-tagged}'[add location to scan (as tagged path)]' \
|
||
|
{-l,--load-script}'[show `script` in editor view]' \
|
||
|
'*'{-v,--verbose}'[be more verbose]' \
|
||
|
'*'{-V,--less-verbose}'[be less verbose]' \
|
||
|
{-c,--show-settings}'[show the settings view]' \
|
||
|
'(- *)--version[show the version of Shredder]' && ret=0
|
||
|
;;
|
||
|
(hash)
|
||
|
_arguments -s -w : \
|
||
|
'(- *)'{-h,--help}'[show help options]' \
|
||
|
{-a,--algorithm}'[digest type \[bLAKE2B\]]:type:_rmlint_algorithm' \
|
||
|
{-t,--num-threads}'[number of hashing threads \[8\]]: :_guard "[0-9]#" "threads [8]"' \
|
||
|
{-b,--buffer-mbytes}'[megabytes read buffer \[256 MB\]]: :_guard "[0-9]#" "buffer (MB) [256]"' \
|
||
|
{-i,--ignore-order}'[print hashes in order completed, not in order entered (reduces memory usage)]' \
|
||
|
'*:file:_files' && ret=0
|
||
|
;;
|
||
|
(dedupe)
|
||
|
_arguments -s -w : \
|
||
|
'-r[enable deduplication of read-only \[btrfs\] snapshots (requires root)]' \
|
||
|
'(-V)*-v' \
|
||
|
'(-v)*-V' \
|
||
|
':src:_files' \
|
||
|
':dst:_files' && ret=0
|
||
|
;;
|
||
|
(reflink)
|
||
|
_arguments -s -w : \
|
||
|
'(-V)*-v' \
|
||
|
'(-v)*-V' \
|
||
|
':file1:_files' \
|
||
|
':file2:_files' && ret=0
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
_rmlint "$@"
|