Skip to content

Commit

Permalink
fix unzip pattern and strip_root should be used together
Browse files Browse the repository at this point in the history
  • Loading branch information
jusito committed Jan 17, 2025
1 parent aee9710 commit 5f52fcd
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 15 deletions.
13 changes: 7 additions & 6 deletions conan/tools/files/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ def rename(conanfile, src, dst):
:param dst: Path to be renamed to.
"""

# FIXME: This function has been copied from legacy. Needs to fix: which() call and wrap subprocess call.
# FIXME: This function has been copied from legacy. Needs to fix: which()
# call and wrap subprocess call.
if os.path.exists(dst):
raise ConanException("rename {} to {} failed, dst exists.".format(src, dst))

Expand Down Expand Up @@ -323,7 +324,7 @@ def print_progress(_, __):
if pattern:
zip_info = [zi for zi in zip_info if fnmatch(zi.filename, pattern)]
if strip_root:
names = [n.replace("\\", "/") for n in z.namelist()]
names = [zi.filename.replace("\\", "/") for zi in zip_info]
common_folder = os.path.commonprefix(names).split("/", 1)[0]
if not common_folder and len(names) > 1:
raise ConanException("The zip file contains more than 1 folder in the root")
Expand Down Expand Up @@ -379,8 +380,11 @@ def untargz(filename, destination=".", pattern=None, strip_root=False, extract_f
else:
members = tarredgzippedFile.getmembers()

if pattern:
members = list(filter(lambda m: fnmatch(m.name, pattern),
tarredgzippedFile.getmembers()))
if strip_root:
names = [n.replace("\\", "/") for n in tarredgzippedFile.getnames()]
names = [member.name.replace("\\", "/") for member in members]
common_folder = os.path.commonprefix(names).split("/", 1)[0]
if not common_folder and len(names) > 1:
raise ConanException("The tgz file contains more than 1 folder in the root")
Expand All @@ -397,9 +401,6 @@ def untargz(filename, destination=".", pattern=None, strip_root=False, extract_f
linkpath = member.linkpath.replace("\\", "/")
member.linkpath = linkpath.split("/", 1)[1]
member.linkname = member.linkpath
if pattern:
members = list(filter(lambda m: fnmatch(m.name, pattern),
tarredgzippedFile.getmembers()))
tarredgzippedFile.extractall(destination, members=members)


Expand Down
136 changes: 127 additions & 9 deletions test/unittests/tools/files/test_zipping.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,149 @@
import os
import zipfile
from os.path import basename
import tarfile
from os.path import join, exists

import pytest

from conan.tools.files import unzip
from conan.test.utils.mocks import ConanFileMock
from conan.test.utils.test_files import temp_folder
from conans.util.files import save
from conan.errors import ConanException


def test_impossible_to_import_untargz():
with pytest.raises(ImportError) as exc:
from conan.tools.files import untargz


def test_unzip():
def create_example_zip(root_file=True, subfolder=False):
tmp_dir = temp_folder()
file_path = os.path.join(tmp_dir, "foo.txt")
save(os.path.join(tmp_dir, "foo.txt"), "bar")
zf = zipfile.ZipFile(os.path.join(tmp_dir, 'zipfile.zip'), mode='w')
zf.write(file_path, basename(file_path))
archive = join(tmp_dir, "zipfile.zip")
zf = zipfile.ZipFile(archive, mode="w")
if root_file:
foo_txt = join(tmp_dir, "foo.txt")
save(foo_txt, "foo-content")
zf.write(foo_txt, "foo.txt")
if subfolder:
src_bar_txt = join(tmp_dir, "src", "bar.txt")
save(src_bar_txt, "bar-content")
zf.write(src_bar_txt, join("src", "bar.txt"))
zf.close()
return archive


def test_unzip():
archive = create_example_zip(subfolder=True)
conanfile = ConanFileMock({})

# Unzip and check permissions are kept
dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir)
assert exists(join(dest_dir, "foo.txt"))
assert exists(join(dest_dir, "src", "bar.txt"))


def test_unzip_with_pattern():
archive = create_example_zip(subfolder=True)
conanfile = ConanFileMock({})

dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir, pattern="foo.txt")
assert exists(join(dest_dir, "foo.txt"))
assert not exists(join(dest_dir, "src", "bar.txt"))


def test_unzip_with_strip_root():
archive = create_example_zip(root_file=False, subfolder=True)
conanfile = ConanFileMock({})

dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir, strip_root=True)
assert exists(join(dest_dir, "bar.txt"))


def test_unzip_with_strip_root_fails():
archive = create_example_zip(root_file=True, subfolder=True)
conanfile = ConanFileMock({})

dest_dir = temp_folder()
with pytest.raises(ConanException):
unzip(conanfile, archive, dest_dir, strip_root=True)


def test_unzip_with_strip_root_and_pattern():
archive = create_example_zip(root_file=True, subfolder=True)
conanfile = ConanFileMock({})

dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir, pattern="src/*", strip_root=True)
assert exists(join(dest_dir, "bar.txt"))
assert not exists(join(dest_dir, "foo.txt"))


def create_example_tar(root_file=True, subfolder=False):
tmp_dir = temp_folder()
tar_path = join(tmp_dir, "file.tgz")
tar = tarfile.open(tar_path, "w:gz")
if root_file:
foo_txt = join(tmp_dir, "foo.txt")
save(foo_txt, "foo-content")
tar.add(foo_txt, "foo.txt")
if subfolder:
src_bar_txt = join(tmp_dir, "src", "bar.txt")
save(src_bar_txt, "bar-content")
tar.add(src_bar_txt, join("src", "bar.txt"))
tar.close()
return tar_path


def test_untargz():
archive = create_example_tar(subfolder=True)
conanfile = ConanFileMock({})

# Unzip and check permissions are kept
dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir)
assert exists(join(dest_dir, "foo.txt"))
assert exists(join(dest_dir, "src", "bar.txt"))


def test_untargz_with_pattern():
archive = create_example_tar(subfolder=True)
conanfile = ConanFileMock({})

dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir, pattern="foo.txt")
assert exists(join(dest_dir, "foo.txt"))
assert not exists(join(dest_dir, "src", "bar.txt"))


def test_untargz_with_strip_root():
archive = create_example_tar(root_file=False, subfolder=True)
conanfile = ConanFileMock({})

# Unzip and check permissions are kept
dest_dir = temp_folder()
unzip(conanfile, archive, dest_dir, strip_root=True)
assert exists(join(dest_dir, "bar.txt"))


def test_untargz_with_strip_root_fails():
archive = create_example_tar(root_file=True, subfolder=True)
conanfile = ConanFileMock({})

# Unzip and check permissions are kept
dest_dir = temp_folder()
with pytest.raises(ConanException):
unzip(conanfile, archive, dest_dir, strip_root=True)


def test_untargz_with_strip_root_and_pattern():
archive = create_example_tar(root_file=True, subfolder=True)
conanfile = ConanFileMock({})

# Unzip and check permissions are kept
dest_dir = temp_folder()
unzip(conanfile, os.path.join(tmp_dir, 'zipfile.zip'), dest_dir)
assert os.path.exists(os.path.join(dest_dir, "foo.txt"))
unzip(conanfile, archive, dest_dir, pattern="src/*", strip_root=True)
assert exists(join(dest_dir, "bar.txt"))
assert not exists(join(dest_dir, "foo.txt"))

0 comments on commit 5f52fcd

Please sign in to comment.