]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/setuptools/archive_util.py
1 """Utilities for extracting common archive formats"""
9 from distutils
.errors
import DistutilsError
11 from ._path
import ensure_directory
14 "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
15 "UnrecognizedFormat", "extraction_drivers", "unpack_directory",
19 class UnrecognizedFormat(DistutilsError
):
20 """Couldn't recognize the archive type"""
23 def default_filter(src
, dst
):
24 """The default progress/filter callback; returns True for all files"""
29 filename
, extract_dir
, progress_filter
=default_filter
,
31 """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
33 `progress_filter` is a function taking two arguments: a source path
34 internal to the archive ('/'-separated), and a filesystem path where it
35 will be extracted. The callback must return the desired extract path
36 (which may be the same as the one passed in), or else ``None`` to skip
37 that file or directory. The callback can thus be used to report on the
38 progress of the extraction, as well as to filter the items extracted or
39 alter their extraction paths.
41 `drivers`, if supplied, must be a non-empty sequence of functions with the
42 same signature as this function (minus the `drivers` argument), that raise
43 ``UnrecognizedFormat`` if they do not support extracting the designated
44 archive type. The `drivers` are tried in sequence until one is found that
45 does not raise an error, or until all are exhausted (in which case
46 ``UnrecognizedFormat`` is raised). If you do not supply a sequence of
47 drivers, the module's ``extraction_drivers`` constant will be used, which
48 means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that
51 for driver
in drivers
or extraction_drivers
:
53 driver(filename
, extract_dir
, progress_filter
)
54 except UnrecognizedFormat
:
59 raise UnrecognizedFormat(
60 "Not a recognized archive type: %s" % filename
64 def unpack_directory(filename
, extract_dir
, progress_filter
=default_filter
):
65 """"Unpack" a directory, using the same interface as for archives
67 Raises ``UnrecognizedFormat`` if `filename` is not a directory
69 if not os
.path
.isdir(filename
):
70 raise UnrecognizedFormat("%s is not a directory" % filename
)
73 filename
: ('', extract_dir
),
75 for base
, dirs
, files
in os
.walk(filename
):
76 src
, dst
= paths
[base
]
78 paths
[os
.path
.join(base
, d
)] = src
+ d
+ '/', os
.path
.join(dst
, d
)
80 target
= os
.path
.join(dst
, f
)
81 target
= progress_filter(src
+ f
, target
)
85 ensure_directory(target
)
86 f
= os
.path
.join(base
, f
)
87 shutil
.copyfile(f
, target
)
88 shutil
.copystat(f
, target
)
91 def unpack_zipfile(filename
, extract_dir
, progress_filter
=default_filter
):
92 """Unpack zip `filename` to `extract_dir`
94 Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined
95 by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation
96 of the `progress_filter` argument.
99 if not zipfile
.is_zipfile(filename
):
100 raise UnrecognizedFormat("%s is not a zip file" % (filename
,))
102 with zipfile
.ZipFile(filename
) as z
:
103 _unpack_zipfile_obj(z
, extract_dir
, progress_filter
)
106 def _unpack_zipfile_obj(zipfile_obj
, extract_dir
, progress_filter
=default_filter
):
107 """Internal/private API used by other parts of setuptools.
108 Similar to ``unpack_zipfile``, but receives an already opened :obj:`zipfile.ZipFile`
109 object instead of a filename.
111 for info
in zipfile_obj
.infolist():
114 # don't extract absolute paths or ones with .. in them
115 if name
.startswith('/') or '..' in name
.split('/'):
118 target
= os
.path
.join(extract_dir
, *name
.split('/'))
119 target
= progress_filter(name
, target
)
122 if name
.endswith('/'):
124 ensure_directory(target
)
127 ensure_directory(target
)
128 data
= zipfile_obj
.read(info
.filename
)
129 with
open(target
, 'wb') as f
:
131 unix_attributes
= info
.external_attr
>> 16
133 os
.chmod(target
, unix_attributes
)
136 def _resolve_tar_file_or_dir(tar_obj
, tar_member_obj
):
137 """Resolve any links and extract link targets as normal files."""
138 while tar_member_obj
is not None and (
139 tar_member_obj
.islnk() or tar_member_obj
.issym()):
140 linkpath
= tar_member_obj
.linkname
141 if tar_member_obj
.issym():
142 base
= posixpath
.dirname(tar_member_obj
.name
)
143 linkpath
= posixpath
.join(base
, linkpath
)
144 linkpath
= posixpath
.normpath(linkpath
)
145 tar_member_obj
= tar_obj
._getmember
(linkpath
)
148 tar_member_obj
is not None and
149 (tar_member_obj
.isfile() or tar_member_obj
.isdir())
152 return tar_member_obj
154 raise LookupError('Got unknown file type')
157 def _iter_open_tar(tar_obj
, extract_dir
, progress_filter
):
158 """Emit member-destination pairs from a tar archive."""
159 # don't do any chowning!
160 tar_obj
.chown
= lambda *args
: None
162 with contextlib
.closing(tar_obj
):
163 for member
in tar_obj
:
165 # don't extract absolute paths or ones with .. in them
166 if name
.startswith('/') or '..' in name
.split('/'):
169 prelim_dst
= os
.path
.join(extract_dir
, *name
.split('/'))
172 member
= _resolve_tar_file_or_dir(tar_obj
, member
)
176 final_dst
= progress_filter(name
, prelim_dst
)
180 if final_dst
.endswith(os
.sep
):
181 final_dst
= final_dst
[:-1]
183 yield member
, final_dst
186 def unpack_tarfile(filename
, extract_dir
, progress_filter
=default_filter
):
187 """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
189 Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined
190 by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
191 of the `progress_filter` argument.
194 tarobj
= tarfile
.open(filename
)
195 except tarfile
.TarError
as e
:
196 raise UnrecognizedFormat(
197 "%s is not a compressed or uncompressed tar file" % (filename
,)
200 for member
, final_dst
in _iter_open_tar(
201 tarobj
, extract_dir
, progress_filter
,
205 tarobj
._extract
_member
(member
, final_dst
)
206 except tarfile
.ExtractError
:
207 # chown/chmod/mkfifo/mknode/makedev failed
213 extraction_drivers
= unpack_directory
, unpack_zipfile
, unpack_tarfile