]> jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/setuptools/_distutils/archive_util.py
init: venv aand flask
[dlqueue.git] / venv / lib / python3.11 / site-packages / setuptools / _distutils / archive_util.py
1 """distutils.archive_util
2
3 Utility functions for creating archive files (tarballs, zip files,
4 that sort of thing)."""
5
6 import os
7 from warnings import warn
8 import sys
9
10 try:
11 import zipfile
12 except ImportError:
13 zipfile = None
14
15
16 from .errors import DistutilsExecError
17 from .spawn import spawn
18 from .dir_util import mkpath
19 from ._log import log
20
21 try:
22 from pwd import getpwnam
23 except ImportError:
24 getpwnam = None
25
26 try:
27 from grp import getgrnam
28 except ImportError:
29 getgrnam = None
30
31
32 def _get_gid(name):
33 """Returns a gid, given a group name."""
34 if getgrnam is None or name is None:
35 return None
36 try:
37 result = getgrnam(name)
38 except KeyError:
39 result = None
40 if result is not None:
41 return result[2]
42 return None
43
44
45 def _get_uid(name):
46 """Returns an uid, given a user name."""
47 if getpwnam is None or name is None:
48 return None
49 try:
50 result = getpwnam(name)
51 except KeyError:
52 result = None
53 if result is not None:
54 return result[2]
55 return None
56
57
58 def make_tarball(
59 base_name, base_dir, compress="gzip", verbose=0, dry_run=0, owner=None, group=None
60 ):
61 """Create a (possibly compressed) tar file from all the files under
62 'base_dir'.
63
64 'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or
65 None. ("compress" will be deprecated in Python 3.2)
66
67 'owner' and 'group' can be used to define an owner and a group for the
68 archive that is being built. If not provided, the current owner and group
69 will be used.
70
71 The output tar file will be named 'base_dir' + ".tar", possibly plus
72 the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z").
73
74 Returns the output filename.
75 """
76 tar_compression = {
77 'gzip': 'gz',
78 'bzip2': 'bz2',
79 'xz': 'xz',
80 None: '',
81 'compress': '',
82 }
83 compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', 'compress': '.Z'}
84
85 # flags for compression program, each element of list will be an argument
86 if compress is not None and compress not in compress_ext.keys():
87 raise ValueError(
88 "bad value for 'compress': must be None, 'gzip', 'bzip2', "
89 "'xz' or 'compress'"
90 )
91
92 archive_name = base_name + '.tar'
93 if compress != 'compress':
94 archive_name += compress_ext.get(compress, '')
95
96 mkpath(os.path.dirname(archive_name), dry_run=dry_run)
97
98 # creating the tarball
99 import tarfile # late import so Python build itself doesn't break
100
101 log.info('Creating tar archive')
102
103 uid = _get_uid(owner)
104 gid = _get_gid(group)
105
106 def _set_uid_gid(tarinfo):
107 if gid is not None:
108 tarinfo.gid = gid
109 tarinfo.gname = group
110 if uid is not None:
111 tarinfo.uid = uid
112 tarinfo.uname = owner
113 return tarinfo
114
115 if not dry_run:
116 tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress])
117 try:
118 tar.add(base_dir, filter=_set_uid_gid)
119 finally:
120 tar.close()
121
122 # compression using `compress`
123 if compress == 'compress':
124 warn("'compress' is deprecated.", DeprecationWarning)
125 # the option varies depending on the platform
126 compressed_name = archive_name + compress_ext[compress]
127 if sys.platform == 'win32':
128 cmd = [compress, archive_name, compressed_name]
129 else:
130 cmd = [compress, '-f', archive_name]
131 spawn(cmd, dry_run=dry_run)
132 return compressed_name
133
134 return archive_name
135
136
137 def make_zipfile(base_name, base_dir, verbose=0, dry_run=0): # noqa: C901
138 """Create a zip file from all the files under 'base_dir'.
139
140 The output zip file will be named 'base_name' + ".zip". Uses either the
141 "zipfile" Python module (if available) or the InfoZIP "zip" utility
142 (if installed and found on the default search path). If neither tool is
143 available, raises DistutilsExecError. Returns the name of the output zip
144 file.
145 """
146 zip_filename = base_name + ".zip"
147 mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
148
149 # If zipfile module is not available, try spawning an external
150 # 'zip' command.
151 if zipfile is None:
152 if verbose:
153 zipoptions = "-r"
154 else:
155 zipoptions = "-rq"
156
157 try:
158 spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run)
159 except DistutilsExecError:
160 # XXX really should distinguish between "couldn't find
161 # external 'zip' command" and "zip failed".
162 raise DistutilsExecError(
163 (
164 "unable to create zip file '%s': "
165 "could neither import the 'zipfile' module nor "
166 "find a standalone zip utility"
167 )
168 % zip_filename
169 )
170
171 else:
172 log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
173
174 if not dry_run:
175 try:
176 zip = zipfile.ZipFile(
177 zip_filename, "w", compression=zipfile.ZIP_DEFLATED
178 )
179 except RuntimeError:
180 zip = zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_STORED)
181
182 with zip:
183 if base_dir != os.curdir:
184 path = os.path.normpath(os.path.join(base_dir, ''))
185 zip.write(path, path)
186 log.info("adding '%s'", path)
187 for dirpath, dirnames, filenames in os.walk(base_dir):
188 for name in dirnames:
189 path = os.path.normpath(os.path.join(dirpath, name, ''))
190 zip.write(path, path)
191 log.info("adding '%s'", path)
192 for name in filenames:
193 path = os.path.normpath(os.path.join(dirpath, name))
194 if os.path.isfile(path):
195 zip.write(path, path)
196 log.info("adding '%s'", path)
197
198 return zip_filename
199
200
201 ARCHIVE_FORMATS = {
202 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
203 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
204 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"),
205 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
206 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
207 'zip': (make_zipfile, [], "ZIP file"),
208 }
209
210
211 def check_archive_formats(formats):
212 """Returns the first format from the 'format' list that is unknown.
213
214 If all formats are known, returns None
215 """
216 for format in formats:
217 if format not in ARCHIVE_FORMATS:
218 return format
219 return None
220
221
222 def make_archive(
223 base_name,
224 format,
225 root_dir=None,
226 base_dir=None,
227 verbose=0,
228 dry_run=0,
229 owner=None,
230 group=None,
231 ):
232 """Create an archive file (eg. zip or tar).
233
234 'base_name' is the name of the file to create, minus any format-specific
235 extension; 'format' is the archive format: one of "zip", "tar", "gztar",
236 "bztar", "xztar", or "ztar".
237
238 'root_dir' is a directory that will be the root directory of the
239 archive; ie. we typically chdir into 'root_dir' before creating the
240 archive. 'base_dir' is the directory where we start archiving from;
241 ie. 'base_dir' will be the common prefix of all files and
242 directories in the archive. 'root_dir' and 'base_dir' both default
243 to the current directory. Returns the name of the archive file.
244
245 'owner' and 'group' are used when creating a tar archive. By default,
246 uses the current owner and group.
247 """
248 save_cwd = os.getcwd()
249 if root_dir is not None:
250 log.debug("changing into '%s'", root_dir)
251 base_name = os.path.abspath(base_name)
252 if not dry_run:
253 os.chdir(root_dir)
254
255 if base_dir is None:
256 base_dir = os.curdir
257
258 kwargs = {'dry_run': dry_run}
259
260 try:
261 format_info = ARCHIVE_FORMATS[format]
262 except KeyError:
263 raise ValueError("unknown archive format '%s'" % format)
264
265 func = format_info[0]
266 for arg, val in format_info[1]:
267 kwargs[arg] = val
268
269 if format != 'zip':
270 kwargs['owner'] = owner
271 kwargs['group'] = group
272
273 try:
274 filename = func(base_name, base_dir, **kwargs)
275 finally:
276 if root_dir is not None:
277 log.debug("changing back to '%s'", save_cwd)
278 os.chdir(save_cwd)
279
280 return filename