summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2023-03-13 22:52:37 +0200
committerGitHub <noreply@github.com>2023-03-13 22:52:37 +0200
commit934fe177ff912c8e03d5ae951d3805e1fd90ba5e (patch)
tree39933c5d9d3817cce927f46f5340a43bdaf651d6
parent26d2e0d18830b31f42c67715b68504b50e13021c (diff)
downloadwheel-git-934fe177ff912c8e03d5ae951d3805e1fd90ba5e.tar.gz
Changed `wheel unpack` to honor the original permissions of files (#514)
Fixes #505.
-rw-r--r--docs/news.rst1
-rw-r--r--src/wheel/cli/unpack.py9
-rw-r--r--tests/cli/test_unpack.py24
3 files changed, 33 insertions, 1 deletions
diff --git a/docs/news.rst b/docs/news.rst
index 4961729..2fbe136 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -4,6 +4,7 @@ Release Notes
**UNRELEASED**
- Updated vendored ``packaging`` to 23.0
+- ``wheel unpack`` now preserves the executable attribute of extracted files
- Fixed spaces in platform names not being converted to underscores (PR by David Tucker)
- Fixed ``RECORD`` files in generated wheels missing the regular file attribute
- Fixed ``DeprecationWarning`` about the use of the deprecated ``pkg_resources`` API
diff --git a/src/wheel/cli/unpack.py b/src/wheel/cli/unpack.py
index c6409d4..d48840e 100644
--- a/src/wheel/cli/unpack.py
+++ b/src/wheel/cli/unpack.py
@@ -18,6 +18,13 @@ def unpack(path: str, dest: str = ".") -> None:
namever = wf.parsed_filename.group("namever")
destination = Path(dest) / namever
print(f"Unpacking to: {destination}...", end="", flush=True)
- wf.extractall(destination)
+ for zinfo in wf.filelist:
+ wf.extract(zinfo, destination)
+
+ # Set permissions to the same values as they were set in the archive
+ # We have to do this manually due to
+ # https://github.com/python/cpython/issues/59999
+ permissions = zinfo.external_attr >> 16 & 0o777
+ destination.joinpath(zinfo.filename).chmod(permissions)
print("OK")
diff --git a/tests/cli/test_unpack.py b/tests/cli/test_unpack.py
index e6a38bb..ae584af 100644
--- a/tests/cli/test_unpack.py
+++ b/tests/cli/test_unpack.py
@@ -1,6 +1,12 @@
from __future__ import annotations
+import platform
+import stat
+
+import pytest
+
from wheel.cli.unpack import unpack
+from wheel.wheelfile import WheelFile
def test_unpack(wheel_paths, tmp_path):
@@ -10,3 +16,21 @@ def test_unpack(wheel_paths, tmp_path):
"""
for wheel_path in wheel_paths:
unpack(wheel_path, str(tmp_path))
+
+
+@pytest.mark.skipif(
+ platform.system() == "Windows", reason="Windows does not support the executable bit"
+)
+def test_unpack_executable_bit(tmp_path):
+ wheel_path = tmp_path / "test-1.0-py3-none-any.whl"
+ script_path = tmp_path / "script"
+ script_path.write_bytes(b"test script")
+ script_path.chmod(0o755)
+ with WheelFile(wheel_path, "w") as wf:
+ wf.write(str(script_path), "nested/script")
+
+ script_path.unlink()
+ script_path = tmp_path / "test-1.0" / "nested" / "script"
+ unpack(str(wheel_path), str(tmp_path))
+ assert not script_path.is_dir()
+ assert stat.S_IMODE(script_path.stat().st_mode) == 0o755