Hello all! On Thursday 17 of April 2014 15:57:11 Ville Skyttä wrote: > On Mon, Apr 14, 2014 at 4:10 PM, Pavel Raiskup <prais...@redhat.com> wrote: > > +# Everything is parsed from `tar --help` output > > Have you tested this with tar implementations that don't do --help > and/or output something very different for it than GNU tar, for example > the Solaris and BSD tars? What's the expected outcome with them? Even > though the completion file says "for GNU tar", in practice it is being > used with other tars as well.
I tried to rework the patch to not rush non-GNU tar users, for such tars the _posix_tar completion is used. It would be so nice if that could become in upcoming bash-completion release :). Pavel
>From b517df19bb643e7c3905f15521f6091198797f6b Mon Sep 17 00:00:00 2001 From: Pavel Raiskup <prais...@redhat.com> Date: Tue, 11 Mar 2014 19:05:57 +0100 Subject: [PATCH] tar: rework the completion completely Use the parsed 'tar --help' output for completion, at least for GNU tar. For non-GNU tars use the _posix_tar completion. Adjust the testsuite to cover some improvements. --- completions/bsdtar | 1 + completions/star | 1 + completions/tar | 768 ++++++++++++++++++++++++++++++++++----- test/fixtures/tar/archive.tar.xz | Bin 0 -> 10240 bytes test/fixtures/tar/dir/fileA | 0 test/fixtures/tar/dir/fileB | 0 test/fixtures/tar/dir/fileC | 0 test/fixtures/tar/dir/hello | 0 test/fixtures/tar/escape.tar | Bin 0 -> 10240 bytes test/lib/completions/tar.exp | 111 +++++- 10 files changed, 790 insertions(+), 91 deletions(-) create mode 120000 completions/bsdtar create mode 120000 completions/star create mode 100644 test/fixtures/tar/archive.tar.xz create mode 100644 test/fixtures/tar/dir/fileA create mode 100644 test/fixtures/tar/dir/fileB create mode 100644 test/fixtures/tar/dir/fileC create mode 100644 test/fixtures/tar/dir/hello create mode 100644 test/fixtures/tar/escape.tar diff --git a/completions/bsdtar b/completions/bsdtar new file mode 120000 index 0000000..e1d18b0 --- /dev/null +++ b/completions/bsdtar @@ -0,0 +1 @@ +tar \ No newline at end of file diff --git a/completions/star b/completions/star new file mode 120000 index 0000000..e1d18b0 --- /dev/null +++ b/completions/star @@ -0,0 +1 @@ +tar \ No newline at end of file diff --git a/completions/tar b/completions/tar index 8d867d0..dc053a1 100644 --- a/completions/tar +++ b/completions/tar @@ -1,37 +1,455 @@ # bash completion for GNU tar -*- shell-script -*- +# +# General info +# ============ +# +# The "old" style arguments +# ------------------------- +# +# We don't "advice" the old tar option format by default for GNU tar, example: +# +# 'tar czfT /tmp/archive.tar patterns.txt' +# +# We rather advice the 'tar -czf /tmp/archive.tar -T patterns.txt' format of +# arguments. Though, if user starts the 'first' tar argument without leading +# dash, we treat the command line apropriately. +# +# +# long/short options origin +# ------------------------- +# +# For GNU tar, everything is parsed from `tar --help` output so not so much +# per-distribution work should be needed. The _parse_help does not seem to be +# good enough so parsed here directly. +# +# +# FIXME: --starting-file (-K) (should be matched for extraction only) +# FIXME: handle already used (at least short) options +# FIXME: Test-cases for make check. +# - check for no global variable pollution +# FIXME: why PS4='$BASH_SOURCE:$LINENO: ' shows sometimes negative lines? +# FIXME: timeout on tarball listing +# FIXME: cache 'tar --help' parsing results into global variables +# FIXME: at least 'tar -<tab>' should show some helping text (apart from just +# pure option advices) +# FIXME: short option completion should be more intuitive +# - verbose mode option should be adviced multiple times +# - mode option should be adviced only once +# - format option should be adviced only once +# ... -_tar() +__gtar_parse_help_opt() { - local cur prev words cword split - _init_completion -s || return + local opttype arg opt separator optvar + opttype=long + arg="$2" + opt="$1" + separator=" " - local ext regex tar untar + case "$opt" in + --*) + ;; + -\?) + return ;; + -*) + opttype=short + opt=${opt##-} + separator= + ;; + *) + echo >&2 "not an option $opt" + return 1 + ;; + esac - if [[ $cword -eq 1 ]]; then - COMPREPLY=( $( compgen -W 'c t x u r d A' -- "$cur" ) ) + # Remove arguments. + opt=${opt//\[*/} + opt=${opt//=*/=} + + # Basic sanity. + opt=${opt//\"*/} + opt=${opt//\'*/} + opt=${opt//\;*/} + + optvar=$opttype'_arg_'$arg + + eval "$optvar=\"\$$optvar$separator\"\"$opt\"" +} + + +__gtar_parse_help_line() +{ + local i + + for i in $1; do + case "$i" in + # regular options + --*|-*) + __gtar_parse_help_opt "$i" "$2" + ;; + + # end once there is single non-option word + *) + break; + esac + done +} + + +__gnu_tar_parse_help() +{ + local str line arg + while IFS= read line; do + # Ok, this requires some comment probably. The GNU help output prints + # options on lines beginning with spaces. After that, there is one + # or more options separated by ', ' separator string. We are matching + # like this then: ^<spaces>(<separator>?<option>)+<whatever>$ + if [[ "$line" =~ \ + ^[[:blank:]]{1,10}(((,[[:blank:]])?(--?([\]\[a-zA-Z0-9?-=]+))(,[[:space:]])?)+).*$ ]]; then + + line=${BASH_REMATCH[1]} + str="${line//,/ }" + + # Detect that all options on this line accept arguments (and whether + # the arguments are required or not). Note that only long option + # description in GNU help output mentions arguments. So the $line + # variable may contain e.g. '-X, --XXX[=NAME], -XXX2[=NAME]'. + arg=none + if [[ "$line" =~ --[A-Za-z0-9-]+(\[?)= ]]; then + test -n "${BASH_REMATCH[1]}" && arg=opt || arg=req + fi + + __gtar_parse_help_line "$str" "$arg" + fi + done <<<"$(tar --help)" + + long_opts="\ + $long_arg_none\ + $long_arg_opt\ + $long_arg_req" + + short_opts="$short_arg_none$short_arg_opt$short_arg_req" +} + + +# Hack: parse --warning keywords from tar's error output +__gtar_parse_warnings() +{ + while IFS= read line; do + if [[ $line =~ ^[[:blank:]]*-[[:blank:]]*[\`\']([a-zA-Z0-9-]+)\'$ ]]; then + echo "${BASH_REMATCH[1]} no-${BASH_REMATCH[1]}" + fi + done <<<"$(LC_ALL=C tar --warning= 2>&1)" +} + + +# Helper to obtain last character of string. +__tar_last_char() +{ + echo "${1: $(( ${#1} - 1))}" +} + + +__tar_parse_old_opt() +{ + local first_word char + + # current word is the first word + test "$cword" -eq 1 -a -n "$cur" -a "${cur:0:1}" != '-' \ + && old_opt_progress=1 + + # check that first argument does not begin with "-" + first_word=${words[1]} + test -n "$first_word" -a "${first_word:0:1}" != "-" \ + && old_opt_used=1 + + # parse the old option (if present) contents to allow later code expect + # corresponding arguments + if test $old_opt_used -eq 1; then + char=${first_word:0:1} + while test -n "$char"; do + if __tar_is_argreq "$char"; then + old_opt_parsed+=("$char") + fi + first_word=${first_word##$char} + char=${first_word:0:1} + done + fi +} + + +# Make the analysis of whole command line. +__tar_preparse_cmdline() +{ + local first_arg my_args tmparg i modes="ctxurdA" + + shift # progname + + __tar_parse_old_opt + + first_arg=1 + for i in "$@"; do + case "$i" in + --delete|--test-label) + tar_mode=${i:2:100} + tar_mode_arg=$i + break + ;; + --*) + # skip + ;; + -*[$modes]*) + tar_mode=${i//[^$modes]/} + tar_mode=${tar_mode:0:1} + tar_mode_arg=$i + break + ;; + *[$modes]*) + # Only the first arg may be "MODE" without leading dash + if test $first_arg -eq 1; then + tar_mode=${i//[^$modes]/} + tar_mode=${tar_mode:0:1} + tar_mode_arg=$i + fi + ;; + esac + first_arg=0 + done +} + + +# Generate completions for -f/--file. +__tar_file_option() +{ + local ext="$1" + + case "$tar_mode" in + c) + # no need to advise user to re-write existing tarball + _filedir -d + ;; + *) + _filedir "$ext" + ;; + esac +} + + +# Returns truth if option requires argument. No equal sign must be pasted. +# Accepts option in format: 'c', '-c', '--create' +__tar_is_argreq() +{ + local opt + opt=$1 + case "$opt" in + -[A-Za-z0-9?]) + [[ "$short_arg_req" =~ ${opt##-} ]] && return 0 + ;; + [A-Za-z0-9?]) + [[ "$short_arg_req" =~ ${opt} ]] && return 0 + ;; + --*) + [[ "$long_arg_req" =~ [[:blank:]]$opt=[[:blank:]] ]] && return 0 + ;; + esac + + return 1 +} + + +# Called only for short parameter +__tar_complete_mode() +{ + local short_modes has_mode rawopt generated \ + allshort_raw_unused allshort_raw \ + filler i + + short_modes="ctx" + test x"$basic_tar" = x && short_modes="ctxurdA" + + # Remove prefix when needed + rawopt=${cur#-} + + # -c -z -x ... => czx + allshort_raw=${short_opts//[- ]/} + + # init the 'mode' option if no option is in ${cur} + if test "$tar_mode" = none; then + + # when user passed something like 'tar cf' do not put the '-' before + filler= + if test -z "$cur" && test x"$basic_tar" = x; then + filler=- + fi + + generated="" + for (( i=0 ; 1; i++ )); do + local c="${short_modes:$i:1}" + test -z "$c" && break + generated+=" $filler$cur$c" + done + + COMPREPLY=( $(compgen -W "$generated" ) ) return 0 fi + # The last short option requires argument, like '-cf<TAB>'. Cut the + # completion here to enforce argument processing. + if test "$old_opt_progress" -eq 0 \ + && __tar_is_argreq "$(__tar_last_char "$cur")"; then + COMPREPLY=( "$cur" ) && return 0 + fi + + allshort_raw_unused=${allshort_raw//[$rawopt]/} + if test "$tar_mode" != none; then + allshort_raw_unused=${allshort_raw_unused//[$short_modes]} + fi + + generated= + for (( i=0 ; 1; i++ )); do + local c="${allshort_raw_unused:$i:1}" + test -z "$c" && break + generated+=" $cur$c" + done + + COMPREPLY=( $( compgen -W "$generated" ) ) + + return 0 +} + + +__gtar_complete_lopts() +{ + local rv + COMPREPLY=( $( compgen -W "$long_opts" -- "$cur" ) ) + rv=$? + [[ $COMPREPLY == *= ]] && compopt -o nospace + return $rv +} + + +__gtar_complete_sopts() +{ + local generated short_mode_opts i c + short_mode_opts="ctxurdA" + generated=${short_opts//[$short_mode_opts]/} + + for (( i=0 ; 1; i++ )); do + c="${allshort_raw_unused:$i:1}" + test -z "$c" && break + generated+=" $cur$c" + done + + COMPREPLY=( $( compgen -W "$generated" -- "$cur" ) ) +} + + +__tar_try_mode() +{ + case "$cur" in + --*) + # posix tar does not support long opts + test -n "$basic_tar" && return 0 + __gtar_complete_lopts + return $? + ;; + + -*) + # posix tar does not support short optios + test -n "$basic_tar" && return 0 + + __tar_complete_mode && return 0 + ;; + + *) + if test "$cword" -eq 1 || test "$tar_mode" = none; then + __tar_complete_mode && return 0 + fi + ;; + esac + return 1 +} + + +__tar_adjust_PREV_from_old_option() +{ + # deal with old style arguments here + # $ tar cfTC # expects this sequence of arguments: + # $ tar cfTC ARCHIVE_FILE PATTERNS_FILE CHANGE_DIR + if test "$old_opt_used" -eq 1 \ + -a "$cword" -gt 1 \ + -a "$cword" -lt $(( ${#old_opt_parsed[@]} + 2 )); + then + # make e.g. 'C' option from 'cffCT' + prev="-${old_opt_parsed[ $cword - 2 ]}" + fi +} + + +__tar_extract_like_mode() +{ + local i + for i in x d t delete; do + test "$tar_mode" = "$i" && return 0 + done + return 1 +} + + +__tar_try_list_archive() +{ + local tarball tarbin untar + + __tar_extract_like_mode || return 1 + + # This all is just to approach directory completion from "virtual" + # directory structure in tarbal (for which the _filedir is unusable) + + set -- "${words[@]}" + tarbin=$1 + untar="tf" + shift + + read tarball <<<"$(printf -- '%s\n' "$@" \ + | sed -n "/^.\{1,\}$regex\$/p" | tee /tmp/jetel)" + if test -n "$tarball"; then + local IFS=$'\n' + COMPREPLY=($(compgen -o filenames -W "$( + while read line; do + printf "%q\n" "$(printf %q"\n" "$line")" + done <<<"$($tarbin $untar "$tarball" 2>/dev/null)" + )" -- "$(printf "%q\n" "$cur")")) + return 0 + fi +} + +__tar_cleanup_prev() +{ + if [[ "$prev" =~ ^-[a-zA-Z0-9?]*$ ]]; then + # transformate '-caf' ~> '-f' + prev="-$(__tar_last_char "$prev")" + fi +} + +__tar_detect_ext() +{ local tars='@(@(tar|gem|spkg)?(.@(Z|[bgx]z|bz2|lz?(ma)))|t@([abglx]z|b?(z)2))' + ext="$tars" + regex='\(\(tar\|gem\|spkg\)\(\.\(Z\|[bgx]z\|bz2\|lz\(ma\)\?\)\)\?\|t\([abglx]z\|bz\?2\)\)' - case ${words[1]} in + case "$tar_mode_arg" in --*) + # Should never happen? ;; ?(-)*[cr]*f) - if [[ $cword -eq 2 ]]; then - ext='@(tar|gem|spkg)' - case ${words[1]} in - *a*) ext="$tars" ;; - *z*) ext='t?(ar.)gz' ;; - *Z*) ext='ta@(r.Z|z)' ;; - *[jy]*) ext='t@(?(ar.)bz?(2)|b2)' ;; - *J*) ext='t?(ar.)xz' ;; - esac - _filedir "$ext" - else - _filedir - fi - return 0 + ext='@(tar|gem|spkg)' + case ${words[1]} in + *a*) ext="$tars" ;; + *z*) ext='t?(ar.)gz' ;; + *Z*) ext='ta@(r.Z|z)' ;; + *[jy]*) ext='t@(?(ar.)bz?(2)|b2)' ;; + *J*) ext='t?(ar.)xz' ;; + esac ;; +([^ZzJjy])f) ext="$tars" @@ -49,84 +467,258 @@ _tar() ext='@(@(tar|gem|spkg).@(lzma|xz)|t[lx]z)' regex='\(\(tar\|gem\|spkg\)\.\(lzma\|xz\)\|t[lx]z\)' ;; - *) - _filedir - return 0 - ;; esac +} - case $prev in - *${ext:-$tars}) - # complete on files in tar file - # - # get name of tar file from command line - tar=$( sed -e 's/^.* \([^ ]*'$regex'\) .*$/\1/' <<<"${words[@]}" ) - # devise how to untar and list it - untar=t${words[1]//[^Jzjyf]/} - - local IFS=$'\n' - COMPREPLY=( $( compgen -W "$( printf '%s\n' $( tar $untar $tar \ - 2>/dev/null ) )" -- "$cur" ) ) - return 0 - ;; - -C|--directory) - _filedir -d - return 0 - ;; - --atime-preserve) - COMPREPLY=( $( compgen -W 'replace system' -- "$cur" ) ) - return 0 - ;; - --group) - COMPREPLY=( $( compgen -g -- "$cur" ) ) - return 0 - ;; - --owner) - COMPREPLY=( $( compgen -u -- "$cur" ) ) - return 0 - ;; - -F|--info-script|--new-volume-script|--rmt-command|--rsh-command|\ - -I|--use-compress-program) - compopt -o filenames - COMPREPLY=( $( compgen -c -- "$cur" ) ) - return 0 - ;; - --volno-file|--add-file|-T|--files-from|-X|--exclude-from|--index-file) + +_gtar() +{ + local long_opts short_opts \ + long_arg_none long_arg_opt long_arg_req \ + short_arg_none short_arg_opt short_arg_req \ + tar_mode tar_mode_arg old_opt_progress=0 \ + old_opt_used=0 old_opt_parsed=() + + # Main mode, e.g. -x or -c (extract/creation) + local tar_mode=none + + # The mode argument, e.g. -cpf or -c + # FIXME: handle long options + local tar_mode_arg= + + if test "$_TAR_OPT_DEBUG" = 1; then + set -x + PS4="\$BASH_SOURCE:\$LINENO: " + fi + + local cur prev words cword split + + _init_completion -s || return + + # Fill the {long,short}_{opts,arg*} + __gnu_tar_parse_help + + __tar_preparse_cmdline "${words[@]}" + + local ext regex tar untar + + __tar_detect_ext + + while true; do # just-for-easy-break while, not looping + __tar_adjust_PREV_from_old_option + __tar_posix_prev_handle && break + __tar_cleanup_prev + + # Handle all options *REQUIRING* argument. Optional arguments are up to + # user (TODO: is there any sane way to deal with this?). This case + # statement successes only if there already is PREV. + case $prev in + -C|--directory) + _filedir -d + break + ;; + --atime-preserve) + COMPREPLY=( $( compgen -W 'replace system' -- "$cur" ) ) + break + ;; + --group) + COMPREPLY=( $( compgen -g -- "$cur" ) ) + break + ;; + --owner) + COMPREPLY=( $( compgen -u -- "$cur" ) ) + break + ;; + -F|--info-script|--new-volume-script|--rmt-command|--rsh-command|\ + -I|--use-compress-program) + compopt -o filenames + COMPREPLY=( $( compgen -c -- "$cur" ) ) + break + ;; + --volno-file|--add-file|-T|--files-from|-X|--exclude-from|\ + --index-file|--listed-incremental|-g) + _filedir + break + ;; + -H|--format) + COMPREPLY=( $( compgen -W 'gnu oldgnu pax posix ustar v7' \ + -- "$cur" ) ) + break + ;; + --quoting-style) + COMPREPLY=( $( compgen -W 'literal shell shell-always c c-maybe + escape locale clocale' -- "$cur" ) ) + break + ;; + --totals) + COMPREPLY=( $( compgen -W 'SIGHUP SIGQUIT SIGINT SIGUSR1 SIGUSR2' \ + -- "$cur" ) ) + break + ;; + --warning) + COMPREPLY=( $( compgen -W "$(__gtar_parse_warnings)" -- "$cur" ) ) + break + ;; + --file|-f|-!(-*)f) + __tar_file_option "$ext" + break + ;; + --*) + # parameter with required argument but no completion yet + [[ " $long_arg_req " =~ \ $prev=\ ]] && break + + # parameter with optional argument passed with =, something like + # --ocurrence=*<TAB> which is not handled above + [[ " $long_arg_opt " =~ \ $prev\ ]] && break + + # if there is some unknown option with '=', for example + # (literally) user does --nonexistent=<TAB>, we do not want + # continue also + $split && break + + # Most probably, when code goes here, the PREV varibale contains + # some string from "$long_arg_none" and we want continue. + ;; + -[a-zA-Z0-9?]) + # argument required but no completion yet + [[ "$short_arg_req" =~ ${prev##-} ]] && break + ;; + esac + + # safety belts + case "$cur" in + -[a-zA-Z0-9]=*) + # e.g. 'tar -c -f=sth' does not what user could expect + break + ;; + esac + + # Handle the main operational mode of tar. We should do it as soon as + # possible. + __tar_try_mode && break + + # handle others + case "$cur" in + --*) + __gtar_complete_lopts + break + ;; + -*) + # called only if it is *not* first parameter + __gtar_complete_sopts + break + ;; + esac + + # the first argument must be "mode" argument or --param, if any of those + # was truth - the 'break' statement would have been already called + test "$cword" -eq 1 && break + + __tar_try_list_archive && break + + # file completion on relevant files + if test $tar_mode != none; then _filedir + fi + + break + done # just-for-easy-break while + + if test "$_TAR_OPT_DEBUG" = 1; then + set +x + unset PS4 + fi + + return 0 +} + + +__tar_posix_prev_handle() +{ + case "$prev" in + -f) + __tar_file_option "$ext" return 0 ;; - -H|--format) - COMPREPLY=( $( compgen -W 'gnu oldgnu pax posix ustar v7' \ - -- "$cur" ) ) - return 0 - ;; - --quoting-style) - COMPREPLY=( $( compgen -W 'literal shell shell-always c c-maybe - escape locale clocale' -- "$cur" ) ) - return 0 - ;; - --totals) - COMPREPLY=( $( compgen -W 'SIGHUP SIGQUIT SIGINT SIGUSR1 SIGUSR2' \ - -- "$cur" ) ) - return 0 - ;; - --occurrence|--sparse-version|--to-command|--mode|--mtime|\ - --tape-length|-b|--blocking-factor|--record-size|-V|--text|--backup|\ - --exclude|--exclude-tag*|-K|--starting-file|-N|--newer|--after-date|\ - --suffix|--strip-components|--transform|--xform|--checkpoint|\ - --checkpoint-action|--no-quote-chars|--quote-chars|--warnings) + -b) return 0 - ;; esac - $split && return 0 + return 1 +} + + +_posix_tar() +{ + local long_opts short_opts basic_tar \ + long_arg_none long_arg_opt long_arg_req \ + short_arg_none short_arg_opt short_arg_req \ + tar_mode tar_mode_arg old_opt_progress=0 \ + old_opt_used=1 old_opt_parsed=() + + # Main mode, e.g. -x or -c (extract/creation) + local tar_mode=none + + # The mode argument, e.g. -cpf or -c + local tar_mode_arg= + + local cur prev words cword split + + _init_completion -s || return + + basic_tar=yes + tar_mode=none + + # relatively compatible modes are {c,t,x} + # relatively compatible options {b,f,m,v,w} + short_arg_req="fb" + short_arg_none="wmv" + short_opts="$short_arg_req$short_arg_none" + + __tar_preparse_cmdline "${words[@]}" + + local ext regex tar untar + + __tar_detect_ext + + __tar_adjust_PREV_from_old_option + + __tar_posix_prev_handle && return 0 + + __tar_try_mode && return + + __tar_try_list_archive && return # file completion on relevant files - _filedir "$ext" + _filedir +} + - return 0 +_tar() +{ + local cmd=${COMP_WORDS[0]} output line + read line <<<"$($cmd --version)" + case "$line" in + *GNU*) + _gtar "$@" + ;; + *) + _posix_tar "$@" + ;; + esac } -[ -n "${COMP_TAR_INTERNAL_PATHS:-}" ] && complete -F _tar -o dirnames tar || - complete -F _tar tar + + +if [ -n "${COMP_TAR_INTERNAL_PATHS:-}" ]; then + complete -F _tar -o dirnames tar + complete -F _gtar -o dirnames gtar + complete -F _posix_tar -o dirnames bsdtar + complete -F _posix_tar -o dirnames star +else + complete -F _tar tar + complete -F _gtar gtar + complete -F _posix_tar bsdtar + complete -F _posix_tar star +fi # ex: ts=4 sw=4 et filetype=sh diff --git a/test/fixtures/tar/archive.tar.xz b/test/fixtures/tar/archive.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..c8d2725640ea851fc536326ecd790c99fef5581f GIT binary patch literal 10240 zcmeIy?+Su26o=tmig(b?=G^D%N&<}}A<?@3oRS36A8|s^yDyU+cO1`;nU~E*tvqx$ zymzXb#5?^whf)|yj5WrK6Q3$AMvPX8Tlrjl`&)ZGG)bcB=1{ihTm9;rpX#sn{rGy` z<$o-zV!z@!L%><q<@!zj67sh?bt=&-o@s1N{(b(t5hVV@y!`Euza{_pNlZJ2`+q8` z>M|`wTbY%A|NpmQQ}T}%z?(*o|Nr*QJ4;Km@)tAQe<A;+?(9bZ0R#|0009ILKmY** c5I_I{1Q0*~0R#|0009ILKmY**5cnT~J3X&%i2wiq literal 0 HcmV?d00001 diff --git a/test/fixtures/tar/dir/fileA b/test/fixtures/tar/dir/fileA new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/tar/dir/fileB b/test/fixtures/tar/dir/fileB new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/tar/dir/fileC b/test/fixtures/tar/dir/fileC new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/tar/dir/hello b/test/fixtures/tar/dir/hello new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/tar/escape.tar b/test/fixtures/tar/escape.tar new file mode 100644 index 0000000000000000000000000000000000000000..7af7e9f21ec74db252d41eee7dddc06b9abd09ba GIT binary patch literal 10240 zcmeIyu?~YE6hKivg>>nt@5z(zq3zOiF<Sq>XqPUgT_B{nEF=<xITuWwD?a)>Vl<a0 ziPnG4+tN0iXiytR3sGDzVo{y9;$N0GSeIv-y?4``?#pAHj`sYve)L}B&r^3fT??Oq zE%49%MRR{u8R%c*=;Z$AmiiAC_Wo-0uhie)TDt%H|3BaVNdH>>Te|<jhWGz}q<@Y6 r?12CR2q1s}0tg_000IagfB*srAb<b@2q1s}0tg_000Iag@E-y%-w|gv literal 0 HcmV?d00001 diff --git a/test/lib/completions/tar.exp b/test/lib/completions/tar.exp index 37f1ae4..70e38d0 100644 --- a/test/lib/completions/tar.exp +++ b/test/lib/completions/tar.exp @@ -2,19 +2,124 @@ proc setup {} { save_env } - proc teardown {} { - assert_env_unmodified + assert_env_unmodified {/OLDPWD=/d} } - setup +# Detect whether system's tar is GNU tar +set cmd "tar --version" +send "$cmd\r" +expect "^$cmd\r\n" +expect { + -re "GNU\[^\n\]*\n" { + set tar_version gnu + } + -re ".*\n" { + set tar_version unknown + } +} +sync_after_int + +set test "old option: list escaped chars" +assert_complete_dir "a/b\\'c/" "tar tf escape.tar a/b\\\'" $::srcdir/fixtures/tar $test +sync_after_int + +# TODO: "tar tf escape.tar a/b" + +set test "check that any completion done" assert_complete_any "tar " +sync_after_int + +# Use bsdtar as the it completes to only 'zc zt zx' ('tar' can be GNU tar and it +# can would have more options) +set test "old option: mode is not on first place" +assert_complete {zc zt zx} "bsdtar z" $test +sync_after_int + +set test "old option: test 'f' when mode is not as a first option" +assert_complete_dir "dir/ dir2/" "tar zfc " $::srcdir/fixtures/tar +sync_after_int + +set test "old option: creating archive and 'f' option" +assert_complete_dir "dir/ dir2/" "tar cf " $::srcdir/fixtures/tar +sync_after_int + +set test "old option: archive listing" +assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar tf archive.tar.xz dir/file" $::srcdir/fixtures/tar +sync_after_int +set test "old option: check _second_ option in \"old\" argument" +assert_complete_dir "dir/ dir2/" "bsdtar cbfvv NOT_EXISTS " $::srcdir/fixtures/tar +sync_after_int +set test "old option: create and members" +assert_complete_dir "dir/ dir2/ archive.tar.xz escape.tar" "tar cTfvv NOT_EXISTS DONT_CREATE.tar " $::srcdir/fixtures/tar sync_after_int +if { "$tar_version" == "gnu" } { + set test "check short options" + assert_complete_any "tar -c" + sync_after_int + + set test "mode not as a first option" + assert_complete_dir "dir/ dir2/" "tar -zcf " $::srcdir/fixtures/tar + sync_after_int + + # Only directories should be completed. + set test "check that we do not suggest re-writing existing archive" + assert_complete_dir "dir/ dir2/" "tar -cf " $::srcdir/fixtures/tar + sync_after_int + + set test "check --file option" + assert_complete_dir "dir/ dir2/" "tar -c --file " $::srcdir/fixtures/tar + sync_after_int + + set test "check --file option #2" + assert_complete_dir "dir/ dir2/" "tar -cvv --file " $::srcdir/fixtures/tar + sync_after_int + + set test "archive listing" + assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar -tf archive.tar.xz dir/file" $::srcdir/fixtures/tar + sync_after_int + + set test "archive listing with --file" + assert_complete_dir "dir/fileA dir/fileB dir/fileC" "tar -t --file archive.tar.xz dir/file" $::srcdir/fixtures/tar + sync_after_int + + # Some random options should work: + set test "test random tar's long option #1" + assert_complete "--blocking-factor= --block-number" "tar --block" $test + sync_after_int + + set test "test random tar's long option #2" + assert_complete "--owner=" "tar --own" $test -nospace + sync_after_int + + set test "test random tar's long option #3" + assert_complete "--posix" "tar -cf /dev/null --posi" $test + sync_after_int + + # --owner + set users [exec bash -c "compgen -A user"] + set test "test --owner option" + assert_complete $users "tar --owner=" $test + sync_after_int + + # --group + set groups [exec bash -c "compgen -A group"] + set test "test --group option" + assert_complete $groups "tar --group=" $test + sync_after_int + + # use -b for this as -b is still not handled by tar's completion + set test "short opt -XXXb <TAB> (arg required)" + assert_no_complete "tar -cvvfb " $test + sync_after_int + + # TODO: how to test that 'tar -cf<TAB>' completes to 'tar -cf ' +} teardown -- 1.9.3
_______________________________________________ Bash-completion-devel mailing list Bash-completion-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/bash-completion-devel