Skip to content

Commit

Permalink
Changed wheel unpack to honor the original permissions of files (#514)
Browse files Browse the repository at this point in the history
Fixes #505.
  • Loading branch information
agronholm authored Mar 13, 2023
1 parent 26d2e0d commit 934fe17
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/news.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion src/wheel/cli/unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
24 changes: 24 additions & 0 deletions tests/cli/test_unpack.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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

0 comments on commit 934fe17

Please sign in to comment.