|
18 | 18 | import os
|
19 | 19 | import pkg_resources
|
20 | 20 | import re
|
| 21 | +import stat |
21 | 22 | import zipfile
|
22 | 23 |
|
23 | 24 |
|
| 25 | +def current_umask(): |
| 26 | + """Get the current umask which involves having to set it temporarily.""" |
| 27 | + mask = os.umask(0) |
| 28 | + os.umask(mask) |
| 29 | + return mask |
| 30 | + |
| 31 | + |
| 32 | +def set_extracted_file_to_default_mode_plus_executable(path): |
| 33 | + """ |
| 34 | + Make file present at path have execute for user/group/world |
| 35 | + (chmod +x) is no-op on windows per python docs |
| 36 | + """ |
| 37 | + os.chmod(path, (0o777 & ~current_umask() | 0o111)) |
| 38 | + |
| 39 | + |
24 | 40 | class Wheel(object):
|
25 | 41 |
|
26 | 42 | def __init__(self, path):
|
@@ -107,8 +123,21 @@ def extras(self):
|
107 | 123 | return self.metadata().get('extras', [])
|
108 | 124 |
|
109 | 125 | def expand(self, directory):
|
110 |
| - with zipfile.ZipFile(self.path(), 'r') as whl: |
111 |
| - whl.extractall(directory) |
| 126 | + with zipfile.ZipFile(self.path(), "r", allowZip64=True) as whl: |
| 127 | + whl.extractall(directory) |
| 128 | + # The following logic is borrowed from Pip: |
| 129 | + # https://github.com/pypa/pip/blob/cc48c07b64f338ac5e347d90f6cb4efc22ed0d0b/src/pip/_internal/utils/unpacking.py#L240 |
| 130 | + for info in whl.infolist(): |
| 131 | + name = info.filename |
| 132 | + # Do not attempt to modify directories. |
| 133 | + if name.endswith("/") or name.endswith("\\"): |
| 134 | + continue |
| 135 | + mode = info.external_attr >> 16 |
| 136 | + # if mode and regular file and any execute permissions for |
| 137 | + # user/group/world? |
| 138 | + if mode and stat.S_ISREG(mode) and mode & 0o111: |
| 139 | + name = os.path.join(directory, name) |
| 140 | + set_extracted_file_to_default_mode_plus_executable(name) |
112 | 141 |
|
113 | 142 | # _parse_metadata parses METADATA files according to https://www.python.org/dev/peps/pep-0314/
|
114 | 143 | def _parse_metadata(self, content):
|
|
0 commit comments