xref: /openbmc/qemu/tests/functional/qemu_test/uncompress.py (revision e88a579392f74aa7658299f29dc43aca199e4533)
1ba32e50aSDaniel P. Berrangé# SPDX-License-Identifier: GPL-2.0-or-later
2ba32e50aSDaniel P. Berrangé#
3ba32e50aSDaniel P. Berrangé# Utilities for python-based QEMU tests
4ba32e50aSDaniel P. Berrangé#
5ba32e50aSDaniel P. Berrangé# Copyright 2024 Red Hat, Inc.
6ba32e50aSDaniel P. Berrangé#
7ba32e50aSDaniel P. Berrangé# Authors:
8ba32e50aSDaniel P. Berrangé#  Thomas Huth <thuth@redhat.com>
9ba32e50aSDaniel P. Berrangé
10ba32e50aSDaniel P. Berrangéimport gzip
11ba32e50aSDaniel P. Berrangéimport lzma
12ba32e50aSDaniel P. Berrangéimport os
13e6c9ab0bSAlex Bennéeimport stat
14ba32e50aSDaniel P. Berrangéimport shutil
15dd66e65fSDaniel P. Berrangéfrom urllib.parse import urlparse
16*98139588SDaniel P. Berrangéfrom subprocess import run, CalledProcessError, DEVNULL
17dd66e65fSDaniel P. Berrangé
18dd66e65fSDaniel P. Berrangéfrom .asset import Asset
19ba32e50aSDaniel P. Berrangé
20ba32e50aSDaniel P. Berrangé
21ba32e50aSDaniel P. Berrangédef gzip_uncompress(gz_path, output_path):
22ba32e50aSDaniel P. Berrangé    if os.path.exists(output_path):
23ba32e50aSDaniel P. Berrangé        return
24ba32e50aSDaniel P. Berrangé    with gzip.open(gz_path, 'rb') as gz_in:
25ba32e50aSDaniel P. Berrangé        try:
26ba32e50aSDaniel P. Berrangé            with open(output_path, 'wb') as raw_out:
27ba32e50aSDaniel P. Berrangé                shutil.copyfileobj(gz_in, raw_out)
28ba32e50aSDaniel P. Berrangé        except:
29ba32e50aSDaniel P. Berrangé            os.remove(output_path)
30ba32e50aSDaniel P. Berrangé            raise
31ba32e50aSDaniel P. Berrangé
32ba32e50aSDaniel P. Berrangédef lzma_uncompress(xz_path, output_path):
33ba32e50aSDaniel P. Berrangé    if os.path.exists(output_path):
34ba32e50aSDaniel P. Berrangé        return
35ba32e50aSDaniel P. Berrangé    with lzma.open(xz_path, 'rb') as lzma_in:
36ba32e50aSDaniel P. Berrangé        try:
37ba32e50aSDaniel P. Berrangé            with open(output_path, 'wb') as raw_out:
38ba32e50aSDaniel P. Berrangé                shutil.copyfileobj(lzma_in, raw_out)
39ba32e50aSDaniel P. Berrangé        except:
40ba32e50aSDaniel P. Berrangé            os.remove(output_path)
41ba32e50aSDaniel P. Berrangé            raise
42dd66e65fSDaniel P. Berrangé
43e6c9ab0bSAlex Bennée
44e6c9ab0bSAlex Bennéedef zstd_uncompress(zstd_path, output_path):
45e6c9ab0bSAlex Bennée    if os.path.exists(output_path):
46e6c9ab0bSAlex Bennée        return
47e6c9ab0bSAlex Bennée
48e6c9ab0bSAlex Bennée    try:
49*98139588SDaniel P. Berrangé        run(['zstd', "-f", "-d", zstd_path,
50*98139588SDaniel P. Berrangé             "-o", output_path], capture_output=True, check=True)
51e6c9ab0bSAlex Bennée    except CalledProcessError as e:
52e6c9ab0bSAlex Bennée        os.remove(output_path)
53e6c9ab0bSAlex Bennée        raise Exception(
54e6c9ab0bSAlex Bennée            f"Unable to decompress zstd file {zstd_path} with {e}") from e
55e6c9ab0bSAlex Bennée
56e6c9ab0bSAlex Bennée    # zstd copies source archive permissions for the output
57e6c9ab0bSAlex Bennée    # file, so must make this writable for QEMU
58e6c9ab0bSAlex Bennée    os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR)
59e6c9ab0bSAlex Bennée
60e6c9ab0bSAlex Bennée
61dd66e65fSDaniel P. Berrangé'''
62dd66e65fSDaniel P. Berrangé@params compressed: filename, Asset, or file-like object to uncompress
63dd66e65fSDaniel P. Berrangé@params uncompressed: filename to uncompress into
64dd66e65fSDaniel P. Berrangé@params format: optional compression format (gzip, lzma)
65dd66e65fSDaniel P. Berrangé
66dd66e65fSDaniel P. BerrangéUncompresses @compressed into @uncompressed
67dd66e65fSDaniel P. Berrangé
68dd66e65fSDaniel P. BerrangéIf @format is None, heuristics will be applied to guess the format
69dd66e65fSDaniel P. Berrangéfrom the filename or Asset URL. @format must be non-None if @uncompressed
70dd66e65fSDaniel P. Berrangéis a file-like object.
71dd66e65fSDaniel P. Berrangé
72dd66e65fSDaniel P. BerrangéReturns the fully qualified path to the uncompessed file
73dd66e65fSDaniel P. Berrangé'''
74dd66e65fSDaniel P. Berrangédef uncompress(compressed, uncompressed, format=None):
75dd66e65fSDaniel P. Berrangé    if format is None:
76dd66e65fSDaniel P. Berrangé        format = guess_uncompress_format(compressed)
77dd66e65fSDaniel P. Berrangé
78dd66e65fSDaniel P. Berrangé    if format == "xz":
79dd66e65fSDaniel P. Berrangé        lzma_uncompress(str(compressed), uncompressed)
80dd66e65fSDaniel P. Berrangé    elif format == "gz":
81dd66e65fSDaniel P. Berrangé        gzip_uncompress(str(compressed), uncompressed)
82e6c9ab0bSAlex Bennée    elif format == "zstd":
83e6c9ab0bSAlex Bennée        zstd_uncompress(str(compressed), uncompressed)
84dd66e65fSDaniel P. Berrangé    else:
85dd66e65fSDaniel P. Berrangé        raise Exception(f"Unknown compression format {format}")
86dd66e65fSDaniel P. Berrangé
87dd66e65fSDaniel P. Berrangé'''
88dd66e65fSDaniel P. Berrangé@params compressed: filename, Asset, or file-like object to guess
89dd66e65fSDaniel P. Berrangé
90dd66e65fSDaniel P. BerrangéGuess the format of @compressed, raising an exception if
91dd66e65fSDaniel P. Berrangéno format can be determined
92dd66e65fSDaniel P. Berrangé'''
93dd66e65fSDaniel P. Berrangédef guess_uncompress_format(compressed):
94dd66e65fSDaniel P. Berrangé    if type(compressed) == Asset:
95dd66e65fSDaniel P. Berrangé        compressed = urlparse(compressed.url).path
96dd66e65fSDaniel P. Berrangé    elif type(compressed) != str:
97dd66e65fSDaniel P. Berrangé        raise Exception(f"Unable to guess compression cformat for {compressed}")
98dd66e65fSDaniel P. Berrangé
99dd66e65fSDaniel P. Berrangé    (name, ext) = os.path.splitext(compressed)
100dd66e65fSDaniel P. Berrangé    if ext == ".xz":
101dd66e65fSDaniel P. Berrangé        return "xz"
102dd66e65fSDaniel P. Berrangé    elif ext == ".gz":
103dd66e65fSDaniel P. Berrangé        return "gz"
104e6c9ab0bSAlex Bennée    elif ext in [".zstd", ".zst"]:
105e6c9ab0bSAlex Bennée        return 'zstd'
106dd66e65fSDaniel P. Berrangé    else:
107dd66e65fSDaniel P. Berrangé        raise Exception(f"Unknown compression format for {compressed}")
108