unarchive: add support for .tar.zst (zstd compression) (#73265)

This commit is contained in:
Jeff Squyres 2021-02-10 00:14:41 -05:00 committed by GitHub
parent ae241b407a
commit 6fd0a74601
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 3 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- unarchive - Add support for .tar.zst (zstd compression) (https://github.com/ansible/ansible/pull/73265).

View file

@ -110,8 +110,9 @@ todo:
- Re-implement zip support using native zipfile module.
notes:
- Requires C(zipinfo) and C(gtar)/C(unzip) command on target host.
- Can handle I(.zip) files using C(unzip) as well as I(.tar), I(.tar.gz), I(.tar.bz2) and I(.tar.xz) files using C(gtar).
- Does not handle I(.gz) files, I(.bz2) files or I(.xz) files that do not contain a I(.tar) archive.
- Requires C(zstd) command on target host to expand I(.tar.zst) files.
- Can handle I(.zip) files using C(unzip) as well as I(.tar), I(.tar.gz), I(.tar.bz2), I(.tar.xz), and I(.tar.zst) files using C(gtar).
- Does not handle I(.gz) files, I(.bz2) files, I(.xz), or I(.zst) files that do not contain a I(.tar) archive.
- Uses gtar's C(--diff) arg to calculate if changed or not. If this C(arg) is not
supported, it will always unpack the archive.
- Existing files/directories in the destination which are not in the archive
@ -891,9 +892,22 @@ class TarXzArchive(TgzArchive):
self.zipflag = '-J'
# Class to handle zstd compressed tar files
class TarZstdArchive(TgzArchive):
def __init__(self, src, b_dest, file_args, module):
super(TarZstdArchive, self).__init__(src, b_dest, file_args, module)
# GNU Tar supports the --use-compress-program option to
# specify which executable to use for
# compression/decompression.
#
# Note: some flavors of BSD tar support --zstd (e.g., FreeBSD
# 12.2), but the TgzArchive class only supports GNU Tar.
self.zipflag = '--use-compress-program=zstd'
# try handlers in order and return the one that works or bail if none work
def pick_handler(src, dest, file_args, module):
handlers = [ZipArchive, TgzArchive, TarArchive, TarBzipArchive, TarXzArchive]
handlers = [ZipArchive, TgzArchive, TarArchive, TarBzipArchive, TarXzArchive, TarZstdArchive]
reasons = set()
for handler in handlers:
obj = handler(src, dest, file_args, module)

View file

@ -4,6 +4,7 @@
- import_tasks: test_tar_gz_creates.yml
- import_tasks: test_tar_gz_owner_group.yml
- import_tasks: test_tar_gz_keep_newer.yml
- import_tasks: test_tar_zst.yml
- import_tasks: test_zip.yml
- import_tasks: test_exclude.yml
- import_tasks: test_include.yml

View file

@ -6,6 +6,13 @@
- unzip
when: ansible_pkg_mgr in ('yum', 'dnf', 'apt', 'pkgng')
- name: Ensure zstd is present, if available
ignore_errors: true
package:
name:
- zstd
when: ansible_pkg_mgr in ('yum', 'dnf', 'apt', 'pkgng')
- name: prep our file
copy:
src: foo.txt
@ -18,6 +25,28 @@
- name: prep a tar.gz file
shell: tar czvf test-unarchive.tar.gz foo-unarchive.txt chdir={{remote_tmp_dir}}
- name: see if we have the zstd executable
ignore_errors: true
shell: zstd --version
register: zstd_available
- when: zstd_available.rc == 0
block:
- name: find gnu tar
shell: |
#!/bin/sh
which gtar 2>/dev/null
if test $? -ne 0; then
if test -z "`tar --version | grep bsdtar`"; then
which tar
fi
fi
register: gnu_tar
- name: prep a tar.zst file
shell: "{{ gnu_tar.stdout }} --use-compress-program=zstd -cvf test-unarchive.tar.zst foo-unarchive.txt chdir={{remote_tmp_dir}}"
when: gnu_tar.stdout != ""
- name: prep a chmodded file for zip
copy:
src: foo.txt

View file

@ -0,0 +1,40 @@
# Only do this whole file when the "zstd" executable is present
- when:
- zstd_available.rc == 0
- gnu_tar.stdout != ""
block:
- name: create our tar.zst unarchive destination
file:
path: '{{remote_tmp_dir}}/test-unarchive-tar-zst'
state: directory
- name: unarchive a tar.zst file
unarchive:
src: '{{remote_tmp_dir}}/test-unarchive.tar.zst'
dest: '{{remote_tmp_dir}}/test-unarchive-tar-zst'
remote_src: yes
register: unarchive02
- name: verify that the file was marked as changed
assert:
that:
- "unarchive02.changed == true"
# Verify that no file list is generated
- "'files' not in unarchive02"
- name: verify that the file was unarchived
file:
path: '{{remote_tmp_dir}}/test-unarchive-tar-zst/foo-unarchive.txt'
state: file
- name: remove our tar.zst unarchive destination
file:
path: '{{remote_tmp_dir}}/test-unarchive-tar-zst'
state: absent
- name: test owner/group perms
include_tasks: test_owner_group.yml
vars:
ext: tar.zst
archive: test-unarchive.tar.zst
testfile: foo-unarchive.txt