|
1 | 1 | """Utility class to inspect an extracted wheel directory""" |
2 | 2 | import glob |
3 | 3 | import os |
| 4 | +import stat |
4 | 5 | import zipfile |
5 | 6 | from typing import Dict, Optional, Set |
6 | 7 |
|
7 | 8 | import pkg_resources |
8 | 9 | import pkginfo |
9 | 10 |
|
10 | 11 |
|
| 12 | +def current_umask() -> int: |
| 13 | + """Get the current umask which involves having to set it temporarily.""" |
| 14 | + mask = os.umask(0) |
| 15 | + os.umask(mask) |
| 16 | + return mask |
| 17 | + |
| 18 | + |
| 19 | +def set_extracted_file_to_default_mode_plus_executable(path: str) -> None: |
| 20 | + """ |
| 21 | + Make file present at path have execute for user/group/world |
| 22 | + (chmod +x) is no-op on windows per python docs |
| 23 | + """ |
| 24 | + os.chmod(path, (0o777 & ~current_umask() | 0o111)) |
| 25 | + |
| 26 | + |
11 | 27 | class Wheel: |
12 | 28 | """Representation of the compressed .whl file""" |
13 | 29 |
|
@@ -43,6 +59,19 @@ def dependencies(self, extras_requested: Optional[Set[str]] = None) -> Set[str]: |
43 | 59 | def unzip(self, directory: str) -> None: |
44 | 60 | with zipfile.ZipFile(self.path, "r") as whl: |
45 | 61 | whl.extractall(directory) |
| 62 | + # The following logic is borrowed from Pip: |
| 63 | + # https://github.com/pypa/pip/blob/cc48c07b64f338ac5e347d90f6cb4efc22ed0d0b/src/pip/_internal/utils/unpacking.py#L240 |
| 64 | + for info in whl.infolist(): |
| 65 | + name = info.filename |
| 66 | + # Do not attempt to modify directories. |
| 67 | + if name.endswith("/") or name.endswith("\\"): |
| 68 | + continue |
| 69 | + mode = info.external_attr >> 16 |
| 70 | + # if mode and regular file and any execute permissions for |
| 71 | + # user/group/world? |
| 72 | + if mode and stat.S_ISREG(mode) and mode & 0o111: |
| 73 | + name = os.path.join(directory, name) |
| 74 | + set_extracted_file_to_default_mode_plus_executable(name) |
46 | 75 |
|
47 | 76 |
|
48 | 77 | def get_dist_info(wheel_dir: str) -> str: |
|
0 commit comments