Skip to content

Commit

Permalink
feat(tar): use long option compression options
Browse files Browse the repository at this point in the history
Previously we only used single letter options to decide what file
extensions to complete for extracting archives, make it also consider
long options (gnu style).

Co-Authored-By: Koichi Murase <myoga.murase@gmail.com>
  • Loading branch information
yedayak and akinomyoga committed Jun 24, 2024
1 parent ba15cd0 commit 0518a21
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 32 deletions.
90 changes: 58 additions & 32 deletions completions/tar
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,15 @@ _comp_cmd_tar__preparse_cmdline()
case "$i" in
--delete | --test-label | --catenate | --concatenate | --extract | --get | --update | --list | --append | --create)
tar_mode=${i:2:100}
# FIXME: We don't set $tar_mode_arg since it's used for combined
# single letter options, but that means we don't handle
# compression formats.
break
;;
--bzip2 | --xz | --lzip | --lzma | --lzop | --zstd)
tar_compression_mode=${i:2:100}
;;
--gzip | --gunzip | --ungzip)
tar_compression_mode="gzip"
;;
--compress | --uncompress)
tar_compression_mode="compress"
;;
--*)
# skip
Expand Down Expand Up @@ -439,10 +444,15 @@ _comp_cmd_tar__cleanup_prev()
fi
}

_comp_cmd_tar__is_bsdtar()
{
[[ ${COMP_WORDS[0]} == ?(*/)bsdtar ]]
}

_comp_cmd_tar__detect_ext()
{
local tars='@(@(tar|spkg)?(.@(Z|[bgx]z|bz2|lz?(ma|o)|zst))|t@([abglx]z|b?(z)2|zst)|cbt|gem|xbps)'
if [[ ${COMP_WORDS[0]} == ?(*/)bsdtar ]]; then
if _comp_cmd_tar__is_bsdtar; then
# https://github.com/libarchive/libarchive/wiki/LibarchiveFormats
tars=${tars/%\)/|pax|cpio|iso|zip|@(j|x)ar|mtree|a|7z|warc}
if _comp_cmd_tar__extract_like_mode; then
Expand All @@ -455,33 +465,44 @@ _comp_cmd_tar__detect_ext()
fi
ext="$tars"

case "$tar_mode_arg" in
--*)
# FIXME: get correct extensions for long options (gnu style)
;;
?(-)*[cr]*f)
if ! _comp_cmd_tar__extract_like_mode; then
if ! _comp_cmd_tar__is_bsdtar; then
ext='@(tar|gem|spkg|cbt|xpbs)'
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)
# Pass through using defaults above
;;
*[Zz]*f)
ext='@(@(t?(ar.)|spkg.)@(gz|Z)|taz)'
;;
*[jy]*f)
ext='@(t?(ar.)bz?(2)|spkg|tb2)'
;;
*[J]*f)
ext='@(@(tar|spkg).@(lzma|xz)|t[lx]z)'
;;
esac
fi
case $tar_mode_arg:$tar_compression_mode in
*a*:none | *:auto-compress)
ext="$tars"
;;
*z*:none | *:gzip)
ext='t?(ar.)gz'
;;
*Z*:none | *:compress)
ext='ta@(r.Z|z)'
;;
*[jy]*:none | *:bzip2)
ext='t@(?(ar.)bz?(2)|b2)'
;;
*J*:none | *:xz)
ext='t?(ar.)xz'
;;
esac
else
#TODO: lzip, lzma, lzop
case $tar_mode_arg:$tar_compression_mode in
*[Zz]*f:none | *:gzip | *:compress)
ext='@(@(t?(ar.)|spkg.)@(gz|Z)|taz)'
;;
*[jy]*f:none | *:bzip2)
ext='@(t?(ar.)bz?(2)|spkg|tb2)'
;;
*J*f:none | *:xz)
ext='@(@(tar|spkg).@(lzma|xz)|t[lx]z)'
;;
*:zstd)
ext='t?(ar.)zst'
;;
esac
fi
}

_comp_cmd_tar__gnu()
Expand All @@ -496,9 +517,11 @@ _comp_cmd_tar__gnu()
local tar_mode=none

# The mode argument, e.g. -cpf or -c
# FIXME: handle long options
local tar_mode_arg=

# Compression mode - from long options
local tar_compression_mode=none

if [[ -v _comp_cmd_tar__debug ]]; then
set -x
local PS4='$BASH_SOURCE:$LINENO: '
Expand Down Expand Up @@ -683,6 +706,9 @@ _comp_cmd_tar__posix()
# The mode argument, e.g. -cpf or -c
local tar_mode_arg=

# Compression mode - from long options
local tar_compression_mode=none

local cur prev words cword was_split comp_args

_comp_initialize -s -- "$@" || return
Expand Down
5 changes: 5 additions & 0 deletions test/t/test_tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,9 @@ def test_23(self, completion):
def test_24(self, completion):
assert completion == "archive.tar.xz dir/ dir2/".split()

# Test compression detection of gnu style options
@pytest.mark.complete("tar --extract --xz --file ", cwd="tar")
def test_25(self, completion):
assert completion == "archive.tar.xz dir/ dir2/".split()

# TODO: "tar tf escape.tar a/b"

0 comments on commit 0518a21

Please sign in to comment.