From 0b938d33ff0545d763d49a67a2dfee3ad88086f0 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 16 Sep 2023 22:40:26 +1000 Subject: [PATCH] Add alternate unzip implementation (#1692) Turns out Linux and the `zipfile` package don't get along, while Windows and `unzip` don't get along. Provide both implementations, so it always works. --- buildozer/buildops.py | 29 ++++++++++++++++++----------- tests/test_buildops.py | 10 +++++++--- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/buildozer/buildops.py b/buildozer/buildops.py index bd05b57e9..cc08a56f3 100644 --- a/buildozer/buildops.py +++ b/buildozer/buildops.py @@ -22,6 +22,7 @@ import tarfile from threading import Thread from urllib.request import Request, urlopen +from zipfile import ZipFile from buildozer.exceptions import BuildozerCommandException from buildozer.logger import Logger @@ -127,17 +128,23 @@ def file_extract(archive, env, cwd="."): if path.suffix == ".zip": LOGGER.debug("Extracting {0} to {1}".format(archive, cwd)) - assert platform != "win32", "unzip unavailable on Windows" - # This should use python's zipfile library, with suitable handling of - # Unix permissions. - # However, this lead to unexpected config script issues, so sticking to - # unzip for now. - return_code = cmd( - ["unzip", "-q", join(cwd, archive)], cwd=cwd, env=env - ).return_code - if return_code != 0: - raise BuildozerCommandException( - "Unzip gave bad return code: {}".format(return_code)) + if platform == "win32": + # This won't work on Unix/OSX, because Android NDK (for example) + # relies on non-standard handling of file permissions and symbolic + # links that Python's zipfile doesn't support. + # Windows doesn't support them either. + with ZipFile(path, "r") as compressed_file: + compressed_file.extractall(cwd) + return + else: + # This won't work on Windows, because there is no unzip command + # there + return_code = cmd( + ["unzip", "-q", join(cwd, archive)], cwd=cwd, env=env + ).return_code + if return_code != 0: + raise BuildozerCommandException( + "Unzip gave bad return code: {}".format(return_code)) return if path.suffix == ".bin": diff --git a/tests/test_buildops.py b/tests/test_buildops.py index 723d21edb..3335c41bd 100644 --- a/tests/test_buildops.py +++ b/tests/test_buildops.py @@ -241,10 +241,14 @@ def test_extract_file(self): m_logger.reset_mock() nonexistent_path = Path(base_dir) / "nonexistent.zip" - with self.assertRaises(BuildozerCommandException): + try: buildops.file_extract(nonexistent_path, environ) - m_logger.debug.assert_called() - m_logger.error.assert_called() + self.fail("No exception raised") + except FileNotFoundError: + pass # This is raised by zipfile on Windows. + except BuildozerCommandException: + pass # This is raised by cmd when not on Windows. + m_logger.reset_mock() # Create a zip file and unzip it.