From 75405b7b0ae03a1fdf2fdb172d2a50cd5f570162 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Sun, 2 Apr 2023 14:28:01 +0200 Subject: feat(extract): always extract files into its own folder (#11596) --- plugins/extract/extract.plugin.zsh | 84 +++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 33 deletions(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 7b7a2fa4f..c416f49ce 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -29,61 +29,79 @@ EOF local success=0 local extract_dir="${1:t:r}" local file="$1" full_path="${1:A}" + + # Create an extraction directory based on the file name + command mkdir -p "$extract_dir" + builtin cd -q "$extract_dir" + case "${file:l}" in (*.tar.gz|*.tgz) - (( $+commands[pigz] )) && { tar -I pigz -xvf "$file" } || tar zxvf "$file" ;; + (( $+commands[pigz] )) && { tar -I pigz -xvf "$full_path" } || tar zxvf "$full_path" ;; (*.tar.bz2|*.tbz|*.tbz2) - (( $+commands[pbzip2] )) && { tar -I pbzip2 -xvf "$file" } || tar xvjf "$file" ;; + (( $+commands[pbzip2] )) && { tar -I pbzip2 -xvf "$full_path" } || tar xvjf "$full_path" ;; (*.tar.xz|*.txz) - (( $+commands[pixz] )) && { tar -I pixz -xvf "$file" } || { + (( $+commands[pixz] )) && { tar -I pixz -xvf "$full_path" } || { tar --xz --help &> /dev/null \ - && tar --xz -xvf "$file" \ - || xzcat "$file" | tar xvf - } ;; + && tar --xz -xvf "$full_path" \ + || xzcat "$full_path" | tar xvf - } ;; (*.tar.zma|*.tlz) tar --lzma --help &> /dev/null \ - && tar --lzma -xvf "$file" \ - || lzcat "$file" | tar xvf - ;; + && tar --lzma -xvf "$full_path" \ + || lzcat "$full_path" | tar xvf - ;; (*.tar.zst|*.tzst) tar --zstd --help &> /dev/null \ - && tar --zstd -xvf "$file" \ - || zstdcat "$file" | tar xvf - ;; - (*.tar) tar xvf "$file" ;; - (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$file" ;; - (*.tar.lz4) lz4 -c -d "$file" | tar xvf - ;; - (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$file" ;; - (*.gz) (( $+commands[pigz] )) && pigz -dk "$file" || gunzip -k "$file" ;; - (*.bz2) bunzip2 "$file" ;; - (*.xz) unxz "$file" ;; - (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$file" ;; - (*.lz4) lz4 -d "$file" ;; - (*.lzma) unlzma "$file" ;; - (*.z) uncompress "$file" ;; - (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl) unzip "$file" -d "$extract_dir" ;; - (*.rar) unrar x -ad "$file" ;; + && tar --zstd -xvf "$full_path" \ + || zstdcat "$full_path" | tar xvf - ;; + (*.tar) tar xvf "$full_path" ;; + (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$full_path" ;; + (*.tar.lz4) lz4 -c -d "$full_path" | tar xvf - ;; + (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$full_path" ;; + (*.gz) (( $+commands[pigz] )) && pigz -dk "$full_path" || gunzip -k "$full_path" ;; + (*.bz2) bunzip2 "$full_path" ;; + (*.xz) unxz "$full_path" ;; + (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$full_path" ;; + (*.lz4) lz4 -d "$full_path" ;; + (*.lzma) unlzma "$full_path" ;; + (*.z) uncompress "$full_path" ;; + (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl) unzip "$full_path" ;; + (*.rar) unrar x -ad "$full_path" ;; (*.rpm) - command mkdir -p "$extract_dir" && builtin cd -q "$extract_dir" \ - && rpm2cpio "$full_path" | cpio --quiet -id ;; - (*.7z) 7za x "$file" ;; + rpm2cpio "$full_path" | cpio --quiet -id ;; + (*.7z) 7za x "$full_path" ;; (*.deb) - command mkdir -p "$extract_dir/control" "$extract_dir/data" - builtin cd -q "$extract_dir"; ar vx "$full_path" > /dev/null + command mkdir -p "control" "data" + ar vx "$full_path" > /dev/null builtin cd -q control; extract ../control.tar.* builtin cd -q ../data; extract ../data.tar.* builtin cd -q ..; command rm *.tar.* debian-binary ;; - (*.zst) unzstd "$file" ;; - (*.cab) cabextract -d "$extract_dir" "$file" ;; - (*.cpio|*.obscpio) cpio -idmvF "$file" ;; - (*.zpaq) zpaq x "$file" ;; + (*.zst) unzstd "$full_path" ;; + (*.cab) cabextract "$full_path" ;; + (*.cpio|*.obscpio) cpio -idmvF "$full_path" ;; + (*.zpaq) zpaq x "$full_path" ;; (*) echo "extract: '$file' cannot be extracted" >&2 success=1 ;; esac (( success = success > 0 ? success : $? )) - (( success == 0 && remove_archive == 0 )) && rm "$full_path" + (( success == 0 && remove_archive == 0 )) && command rm "$full_path" shift - # Go back to original working directory in case we ran cd previously + # Go back to original working directory + # and remove extraction directory if there was an error builtin cd -q "$pwd" + (( success > 0 )) && command rm -r "$extract_dir" + + # If content of extract dir is a single directory, move its contents up + # Glob flags: + # - D: include files starting with . + # - N: no error if directory is empty + # - Y2: at most give 2 files + local -a content + content=("${extract_dir}"/*(DNY2)) + if [[ ${#content} -eq 1 && -d "${content[1]}" ]]; then + command mv -f "${content[1]}" . + command rmdir "$extract_dir" + fi done } -- cgit v1.2.3-70-g09d2 From d47e1d65f66f9bb2e7a96ba58797b33f0e91a623 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Sun, 2 Apr 2023 16:33:54 +0200 Subject: fix(extract): safely remove extract directory The previous code would remove the extract directory if the command failed. This could be bad because we're not checking if the extract directory already existed (since we're using `mkdir -p`), so it could be possible that the extract operation failed, and we'd be removing a directory that already existed and had files in it. This change only removes the directory if there are no files in it, regardless of whether the extract operation was successful or not. This is much safer. --- plugins/extract/extract.plugin.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index c416f49ce..40e67575f 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -88,9 +88,7 @@ EOF shift # Go back to original working directory - # and remove extraction directory if there was an error builtin cd -q "$pwd" - (( success > 0 )) && command rm -r "$extract_dir" # If content of extract dir is a single directory, move its contents up # Glob flags: @@ -102,6 +100,8 @@ EOF if [[ ${#content} -eq 1 && -d "${content[1]}" ]]; then command mv -f "${content[1]}" . command rmdir "$extract_dir" + elif [[ ${#content} -eq 0 ]]; then + command rmdir "$extract_dir" fi done } -- cgit v1.2.3-70-g09d2 From 49d34d00cdaf132f318700398bf42120ff1af8e7 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Thu, 6 Apr 2023 21:06:16 +0200 Subject: fix(extract): fix conflict if compressed file has a folder of the same name This change fixes the case where the compressed file (e.g. tools.tgz) only contains a folder with the same name (e.g. tools) in its root folder. tools.tgz: |- tools |- fileA.txt |- fileB.txt \- fileC.txt In that case, the "smart" folder creation mechanism will extract the files in a folder "tools", and this extraction folder will contain a single folder with the same name. Before this fix, the tool would try to move out the inside folder to the parent one, but there would already be a folder named "tools", so it would generate a conflict. This change first renames the inside folder to a random string, and only then it is moved outside and the old extraction folder is deleted. --- plugins/extract/extract.plugin.zsh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 40e67575f..34c080653 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -98,8 +98,22 @@ EOF local -a content content=("${extract_dir}"/*(DNY2)) if [[ ${#content} -eq 1 && -d "${content[1]}" ]]; then - command mv -f "${content[1]}" . - command rmdir "$extract_dir" + # The extracted folder (${content[1]}) may have the same name as $extract_dir + # If so, we need to rename it to avoid conflicts in a 3-step process + # + # 1. Move and rename the extracted folder to a temporary random name + # 2. Delete the empty folder + # 3. Rename the extracted folder to the original name + if [[ "${content[1]:t}" == "$extract_dir" ]]; then + # =(:) gives /tmp/zsh, with :t it gives zsh + local tmp_dir==(:); tmp_dir="${tmp_dir:t}" + command mv -f "${content[1]}" "$tmp_dir" \ + && command rmdir "$extract_dir" \ + && command mv -f "$tmp_dir" "$extract_dir" + else + command mv -f "${content[1]}" . \ + && command rmdir "$extract_dir" + fi elif [[ ${#content} -eq 0 ]]; then command rmdir "$extract_dir" fi -- cgit v1.2.3-70-g09d2 From 3a01d7df82157a5f3aef01eab9a940e4cba2283a Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Sun, 21 May 2023 19:58:26 +0200 Subject: fix(extract): fix extract dir naming conflicts Fixes #11642 --- plugins/extract/extract.plugin.zsh | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 34c080653..ee1d38b3f 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -27,12 +27,20 @@ EOF fi local success=0 - local extract_dir="${1:t:r}" local file="$1" full_path="${1:A}" + local extract_dir="${1:t:r}" + + # If there's a file or directory with the same name as the archive + # add a random string to the end of the extract directory + if [[ -e "$extract_dir" ]]; then + local rnd="${(L)"${$(( [##36]$RANDOM*$RANDOM ))}":1:5}" + extract_dir="${extract_dir}-${rnd}" + fi # Create an extraction directory based on the file name command mkdir -p "$extract_dir" builtin cd -q "$extract_dir" + echo "extract: extracting to $extract_dir" >&2 case "${file:l}" in (*.tar.gz|*.tgz) @@ -107,11 +115,13 @@ EOF if [[ "${content[1]:t}" == "$extract_dir" ]]; then # =(:) gives /tmp/zsh, with :t it gives zsh local tmp_dir==(:); tmp_dir="${tmp_dir:t}" - command mv -f "${content[1]}" "$tmp_dir" \ + command mv "${content[1]}" "$tmp_dir" \ && command rmdir "$extract_dir" \ - && command mv -f "$tmp_dir" "$extract_dir" - else - command mv -f "${content[1]}" . \ + && command mv "$tmp_dir" "$extract_dir" + # Otherwise, if the extracted folder name already exists in the current + # directory (because of a previous file / folder), keep the extract_dir + elif [[ ! -e "${content[1]:t}" ]]; then + command mv "${content[1]}" . \ && command rmdir "$extract_dir" fi elif [[ ${#content} -eq 0 ]]; then -- cgit v1.2.3-70-g09d2 From b06663df23b2910a6e542dc114dc7adc2cdce22f Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Sun, 21 May 2023 20:14:32 +0200 Subject: feat(extract): add support for `.zlib` and `.exe` files (#11085) Fixes #11085 --- plugins/extract/README.md | 3 +++ plugins/extract/extract.plugin.zsh | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/README.md b/plugins/extract/README.md index ac4a8e197..c8d98b229 100644 --- a/plugins/extract/README.md +++ b/plugins/extract/README.md @@ -25,6 +25,7 @@ plugins=(... extract) | `cpio` | Cpio archive | | `deb` | Debian package | | `ear` | Enterprise Application aRchive | +| `exe` | Windows executable file | | `gz` | Gzip file | | `ipa` | iOS app package | | `ipsw` | iOS firmware file | @@ -52,9 +53,11 @@ plugins=(... extract) | `txz` | Tarball with lzma2 compression | | `tzst` | Tarball with zstd compression | | `war` | Web Application archive (Java-based) | +| `whl` | Python wheel file | | `xpi` | Mozilla XPI module file | | `xz` | LZMA2 archive | | `zip` | Zip archive | +| `zlib` | zlib archive | | `zst` | Zstandard file (zstd) | | `zpaq` | Zpaq file | diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index ee1d38b3f..b7a823c9f 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -83,9 +83,10 @@ EOF builtin cd -q ../data; extract ../data.tar.* builtin cd -q ..; command rm *.tar.* debian-binary ;; (*.zst) unzstd "$full_path" ;; - (*.cab) cabextract "$full_path" ;; + (*.cab|*.exe) cabextract "$full_path" ;; (*.cpio|*.obscpio) cpio -idmvF "$full_path" ;; (*.zpaq) zpaq x "$full_path" ;; + (*.zlib) zlib-flate -uncompress < "$full_path" > "${file:r}" ;; (*) echo "extract: '$file' cannot be extracted" >&2 success=1 ;; -- cgit v1.2.3-70-g09d2 From 3f477e5da5ee42356f103d2c5cdd478d23bf9f03 Mon Sep 17 00:00:00 2001 From: Marc Cornellà Date: Wed, 23 Aug 2023 13:25:33 +0200 Subject: fix(extract): extraction to directory for single-file .gz (#11852) --- plugins/extract/extract.plugin.zsh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index b7a823c9f..513950f33 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -64,7 +64,7 @@ EOF (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$full_path" ;; (*.tar.lz4) lz4 -c -d "$full_path" | tar xvf - ;; (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$full_path" ;; - (*.gz) (( $+commands[pigz] )) && pigz -dk "$full_path" || gunzip -k "$full_path" ;; + (*.gz) (( $+commands[pigz] )) && pigz -cdk "$full_path" > "${file:t:r}" || gunzip -ck "$full_path" > "${file:t:r}" ;; (*.bz2) bunzip2 "$full_path" ;; (*.xz) unxz "$full_path" ;; (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$full_path" ;; @@ -106,19 +106,19 @@ EOF # - Y2: at most give 2 files local -a content content=("${extract_dir}"/*(DNY2)) - if [[ ${#content} -eq 1 && -d "${content[1]}" ]]; then - # The extracted folder (${content[1]}) may have the same name as $extract_dir + if [[ ${#content} -eq 1 && -e "${content[1]}" ]]; then + # The extracted file/folder (${content[1]}) may have the same name as $extract_dir # If so, we need to rename it to avoid conflicts in a 3-step process # - # 1. Move and rename the extracted folder to a temporary random name + # 1. Move and rename the extracted file/folder to a temporary random name # 2. Delete the empty folder - # 3. Rename the extracted folder to the original name + # 3. Rename the extracted file/folder to the original name if [[ "${content[1]:t}" == "$extract_dir" ]]; then # =(:) gives /tmp/zsh, with :t it gives zsh - local tmp_dir==(:); tmp_dir="${tmp_dir:t}" - command mv "${content[1]}" "$tmp_dir" \ + local tmp_name==(:); tmp_name="${tmp_name:t}" + command mv "${content[1]}" "$tmp_name" \ && command rmdir "$extract_dir" \ - && command mv "$tmp_dir" "$extract_dir" + && command mv "$tmp_name" "$extract_dir" # Otherwise, if the extracted folder name already exists in the current # directory (because of a previous file / folder), keep the extract_dir elif [[ ! -e "${content[1]:t}" ]]; then -- cgit v1.2.3-70-g09d2 From 1f56f2bdc455f2167c10fdbeca10934f5f0cbd99 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Sun, 3 Sep 2023 23:08:19 +0800 Subject: fix(extract): remove extraction file extension for tar (#11873) --- plugins/extract/extract.plugin.zsh | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'plugins/extract/extract.plugin.zsh') diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 513950f33..88d8b0740 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -30,6 +30,11 @@ EOF local file="$1" full_path="${1:A}" local extract_dir="${1:t:r}" + # Remove the .tar extension if the file name is .tar.* + if [[ $extract_dir =~ '\.tar$' ]]; then + extract_dir="${extract_dir:r}" + fi + # If there's a file or directory with the same name as the archive # add a random string to the end of the extract directory if [[ -e "$extract_dir" ]]; then -- cgit v1.2.3-70-g09d2