Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/setuptools/_distutils/command/sdist.py
4804 views
1
"""distutils.command.sdist
2
3
Implements the Distutils 'sdist' command (create a source distribution)."""
4
5
import os
6
import sys
7
from glob import glob
8
from warnings import warn
9
10
from distutils.core import Command
11
from distutils import dir_util
12
from distutils import file_util
13
from distutils import archive_util
14
from distutils.text_file import TextFile
15
from distutils.filelist import FileList
16
from distutils import log
17
from distutils.util import convert_path
18
from distutils.errors import DistutilsTemplateError, DistutilsOptionError
19
20
21
def show_formats():
22
"""Print all possible values for the 'formats' option (used by
23
the "--help-formats" command-line option).
24
"""
25
from distutils.fancy_getopt import FancyGetopt
26
from distutils.archive_util import ARCHIVE_FORMATS
27
formats = []
28
for format in ARCHIVE_FORMATS.keys():
29
formats.append(("formats=" + format, None,
30
ARCHIVE_FORMATS[format][2]))
31
formats.sort()
32
FancyGetopt(formats).print_help(
33
"List of available source distribution formats:")
34
35
36
class sdist(Command):
37
38
description = "create a source distribution (tarball, zip file, etc.)"
39
40
def checking_metadata(self):
41
"""Callable used for the check sub-command.
42
43
Placed here so user_options can view it"""
44
return self.metadata_check
45
46
user_options = [
47
('template=', 't',
48
"name of manifest template file [default: MANIFEST.in]"),
49
('manifest=', 'm',
50
"name of manifest file [default: MANIFEST]"),
51
('use-defaults', None,
52
"include the default file set in the manifest "
53
"[default; disable with --no-defaults]"),
54
('no-defaults', None,
55
"don't include the default file set"),
56
('prune', None,
57
"specifically exclude files/directories that should not be "
58
"distributed (build tree, RCS/CVS dirs, etc.) "
59
"[default; disable with --no-prune]"),
60
('no-prune', None,
61
"don't automatically exclude anything"),
62
('manifest-only', 'o',
63
"just regenerate the manifest and then stop "
64
"(implies --force-manifest)"),
65
('force-manifest', 'f',
66
"forcibly regenerate the manifest and carry on as usual. "
67
"Deprecated: now the manifest is always regenerated."),
68
('formats=', None,
69
"formats for source distribution (comma-separated list)"),
70
('keep-temp', 'k',
71
"keep the distribution tree around after creating " +
72
"archive file(s)"),
73
('dist-dir=', 'd',
74
"directory to put the source distribution archive(s) in "
75
"[default: dist]"),
76
('metadata-check', None,
77
"Ensure that all required elements of meta-data "
78
"are supplied. Warn if any missing. [default]"),
79
('owner=', 'u',
80
"Owner name used when creating a tar file [default: current user]"),
81
('group=', 'g',
82
"Group name used when creating a tar file [default: current group]"),
83
]
84
85
boolean_options = ['use-defaults', 'prune',
86
'manifest-only', 'force-manifest',
87
'keep-temp', 'metadata-check']
88
89
help_options = [
90
('help-formats', None,
91
"list available distribution formats", show_formats),
92
]
93
94
negative_opt = {'no-defaults': 'use-defaults',
95
'no-prune': 'prune' }
96
97
sub_commands = [('check', checking_metadata)]
98
99
READMES = ('README', 'README.txt', 'README.rst')
100
101
def initialize_options(self):
102
# 'template' and 'manifest' are, respectively, the names of
103
# the manifest template and manifest file.
104
self.template = None
105
self.manifest = None
106
107
# 'use_defaults': if true, we will include the default file set
108
# in the manifest
109
self.use_defaults = 1
110
self.prune = 1
111
112
self.manifest_only = 0
113
self.force_manifest = 0
114
115
self.formats = ['gztar']
116
self.keep_temp = 0
117
self.dist_dir = None
118
119
self.archive_files = None
120
self.metadata_check = 1
121
self.owner = None
122
self.group = None
123
124
def finalize_options(self):
125
if self.manifest is None:
126
self.manifest = "MANIFEST"
127
if self.template is None:
128
self.template = "MANIFEST.in"
129
130
self.ensure_string_list('formats')
131
132
bad_format = archive_util.check_archive_formats(self.formats)
133
if bad_format:
134
raise DistutilsOptionError(
135
"unknown archive format '%s'" % bad_format)
136
137
if self.dist_dir is None:
138
self.dist_dir = "dist"
139
140
def run(self):
141
# 'filelist' contains the list of files that will make up the
142
# manifest
143
self.filelist = FileList()
144
145
# Run sub commands
146
for cmd_name in self.get_sub_commands():
147
self.run_command(cmd_name)
148
149
# Do whatever it takes to get the list of files to process
150
# (process the manifest template, read an existing manifest,
151
# whatever). File list is accumulated in 'self.filelist'.
152
self.get_file_list()
153
154
# If user just wanted us to regenerate the manifest, stop now.
155
if self.manifest_only:
156
return
157
158
# Otherwise, go ahead and create the source distribution tarball,
159
# or zipfile, or whatever.
160
self.make_distribution()
161
162
def check_metadata(self):
163
"""Deprecated API."""
164
warn("distutils.command.sdist.check_metadata is deprecated, \
165
use the check command instead", PendingDeprecationWarning)
166
check = self.distribution.get_command_obj('check')
167
check.ensure_finalized()
168
check.run()
169
170
def get_file_list(self):
171
"""Figure out the list of files to include in the source
172
distribution, and put it in 'self.filelist'. This might involve
173
reading the manifest template (and writing the manifest), or just
174
reading the manifest, or just using the default file set -- it all
175
depends on the user's options.
176
"""
177
# new behavior when using a template:
178
# the file list is recalculated every time because
179
# even if MANIFEST.in or setup.py are not changed
180
# the user might have added some files in the tree that
181
# need to be included.
182
#
183
# This makes --force the default and only behavior with templates.
184
template_exists = os.path.isfile(self.template)
185
if not template_exists and self._manifest_is_not_generated():
186
self.read_manifest()
187
self.filelist.sort()
188
self.filelist.remove_duplicates()
189
return
190
191
if not template_exists:
192
self.warn(("manifest template '%s' does not exist " +
193
"(using default file list)") %
194
self.template)
195
self.filelist.findall()
196
197
if self.use_defaults:
198
self.add_defaults()
199
200
if template_exists:
201
self.read_template()
202
203
if self.prune:
204
self.prune_file_list()
205
206
self.filelist.sort()
207
self.filelist.remove_duplicates()
208
self.write_manifest()
209
210
def add_defaults(self):
211
"""Add all the default files to self.filelist:
212
- README or README.txt
213
- setup.py
214
- test/test*.py
215
- all pure Python modules mentioned in setup script
216
- all files pointed by package_data (build_py)
217
- all files defined in data_files.
218
- all files defined as scripts.
219
- all C sources listed as part of extensions or C libraries
220
in the setup script (doesn't catch C headers!)
221
Warns if (README or README.txt) or setup.py are missing; everything
222
else is optional.
223
"""
224
self._add_defaults_standards()
225
self._add_defaults_optional()
226
self._add_defaults_python()
227
self._add_defaults_data_files()
228
self._add_defaults_ext()
229
self._add_defaults_c_libs()
230
self._add_defaults_scripts()
231
232
@staticmethod
233
def _cs_path_exists(fspath):
234
"""
235
Case-sensitive path existence check
236
237
>>> sdist._cs_path_exists(__file__)
238
True
239
>>> sdist._cs_path_exists(__file__.upper())
240
False
241
"""
242
if not os.path.exists(fspath):
243
return False
244
# make absolute so we always have a directory
245
abspath = os.path.abspath(fspath)
246
directory, filename = os.path.split(abspath)
247
return filename in os.listdir(directory)
248
249
def _add_defaults_standards(self):
250
standards = [self.READMES, self.distribution.script_name]
251
for fn in standards:
252
if isinstance(fn, tuple):
253
alts = fn
254
got_it = False
255
for fn in alts:
256
if self._cs_path_exists(fn):
257
got_it = True
258
self.filelist.append(fn)
259
break
260
261
if not got_it:
262
self.warn("standard file not found: should have one of " +
263
', '.join(alts))
264
else:
265
if self._cs_path_exists(fn):
266
self.filelist.append(fn)
267
else:
268
self.warn("standard file '%s' not found" % fn)
269
270
def _add_defaults_optional(self):
271
optional = ['test/test*.py', 'setup.cfg']
272
for pattern in optional:
273
files = filter(os.path.isfile, glob(pattern))
274
self.filelist.extend(files)
275
276
def _add_defaults_python(self):
277
# build_py is used to get:
278
# - python modules
279
# - files defined in package_data
280
build_py = self.get_finalized_command('build_py')
281
282
# getting python files
283
if self.distribution.has_pure_modules():
284
self.filelist.extend(build_py.get_source_files())
285
286
# getting package_data files
287
# (computed in build_py.data_files by build_py.finalize_options)
288
for pkg, src_dir, build_dir, filenames in build_py.data_files:
289
for filename in filenames:
290
self.filelist.append(os.path.join(src_dir, filename))
291
292
def _add_defaults_data_files(self):
293
# getting distribution.data_files
294
if self.distribution.has_data_files():
295
for item in self.distribution.data_files:
296
if isinstance(item, str):
297
# plain file
298
item = convert_path(item)
299
if os.path.isfile(item):
300
self.filelist.append(item)
301
else:
302
# a (dirname, filenames) tuple
303
dirname, filenames = item
304
for f in filenames:
305
f = convert_path(f)
306
if os.path.isfile(f):
307
self.filelist.append(f)
308
309
def _add_defaults_ext(self):
310
if self.distribution.has_ext_modules():
311
build_ext = self.get_finalized_command('build_ext')
312
self.filelist.extend(build_ext.get_source_files())
313
314
def _add_defaults_c_libs(self):
315
if self.distribution.has_c_libraries():
316
build_clib = self.get_finalized_command('build_clib')
317
self.filelist.extend(build_clib.get_source_files())
318
319
def _add_defaults_scripts(self):
320
if self.distribution.has_scripts():
321
build_scripts = self.get_finalized_command('build_scripts')
322
self.filelist.extend(build_scripts.get_source_files())
323
324
def read_template(self):
325
"""Read and parse manifest template file named by self.template.
326
327
(usually "MANIFEST.in") The parsing and processing is done by
328
'self.filelist', which updates itself accordingly.
329
"""
330
log.info("reading manifest template '%s'", self.template)
331
template = TextFile(self.template, strip_comments=1, skip_blanks=1,
332
join_lines=1, lstrip_ws=1, rstrip_ws=1,
333
collapse_join=1)
334
335
try:
336
while True:
337
line = template.readline()
338
if line is None: # end of file
339
break
340
341
try:
342
self.filelist.process_template_line(line)
343
# the call above can raise a DistutilsTemplateError for
344
# malformed lines, or a ValueError from the lower-level
345
# convert_path function
346
except (DistutilsTemplateError, ValueError) as msg:
347
self.warn("%s, line %d: %s" % (template.filename,
348
template.current_line,
349
msg))
350
finally:
351
template.close()
352
353
def prune_file_list(self):
354
"""Prune off branches that might slip into the file list as created
355
by 'read_template()', but really don't belong there:
356
* the build tree (typically "build")
357
* the release tree itself (only an issue if we ran "sdist"
358
previously with --keep-temp, or it aborted)
359
* any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories
360
"""
361
build = self.get_finalized_command('build')
362
base_dir = self.distribution.get_fullname()
363
364
self.filelist.exclude_pattern(None, prefix=build.build_base)
365
self.filelist.exclude_pattern(None, prefix=base_dir)
366
367
if sys.platform == 'win32':
368
seps = r'/|\\'
369
else:
370
seps = '/'
371
372
vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr',
373
'_darcs']
374
vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps)
375
self.filelist.exclude_pattern(vcs_ptrn, is_regex=1)
376
377
def write_manifest(self):
378
"""Write the file list in 'self.filelist' (presumably as filled in
379
by 'add_defaults()' and 'read_template()') to the manifest file
380
named by 'self.manifest'.
381
"""
382
if self._manifest_is_not_generated():
383
log.info("not writing to manually maintained "
384
"manifest file '%s'" % self.manifest)
385
return
386
387
content = self.filelist.files[:]
388
content.insert(0, '# file GENERATED by distutils, do NOT edit')
389
self.execute(file_util.write_file, (self.manifest, content),
390
"writing manifest file '%s'" % self.manifest)
391
392
def _manifest_is_not_generated(self):
393
# check for special comment used in 3.1.3 and higher
394
if not os.path.isfile(self.manifest):
395
return False
396
397
fp = open(self.manifest)
398
try:
399
first_line = fp.readline()
400
finally:
401
fp.close()
402
return first_line != '# file GENERATED by distutils, do NOT edit\n'
403
404
def read_manifest(self):
405
"""Read the manifest file (named by 'self.manifest') and use it to
406
fill in 'self.filelist', the list of files to include in the source
407
distribution.
408
"""
409
log.info("reading manifest file '%s'", self.manifest)
410
with open(self.manifest) as manifest:
411
for line in manifest:
412
# ignore comments and blank lines
413
line = line.strip()
414
if line.startswith('#') or not line:
415
continue
416
self.filelist.append(line)
417
418
def make_release_tree(self, base_dir, files):
419
"""Create the directory tree that will become the source
420
distribution archive. All directories implied by the filenames in
421
'files' are created under 'base_dir', and then we hard link or copy
422
(if hard linking is unavailable) those files into place.
423
Essentially, this duplicates the developer's source tree, but in a
424
directory named after the distribution, containing only the files
425
to be distributed.
426
"""
427
# Create all the directories under 'base_dir' necessary to
428
# put 'files' there; the 'mkpath()' is just so we don't die
429
# if the manifest happens to be empty.
430
self.mkpath(base_dir)
431
dir_util.create_tree(base_dir, files, dry_run=self.dry_run)
432
433
# And walk over the list of files, either making a hard link (if
434
# os.link exists) to each one that doesn't already exist in its
435
# corresponding location under 'base_dir', or copying each file
436
# that's out-of-date in 'base_dir'. (Usually, all files will be
437
# out-of-date, because by default we blow away 'base_dir' when
438
# we're done making the distribution archives.)
439
440
if hasattr(os, 'link'): # can make hard links on this system
441
link = 'hard'
442
msg = "making hard links in %s..." % base_dir
443
else: # nope, have to copy
444
link = None
445
msg = "copying files to %s..." % base_dir
446
447
if not files:
448
log.warn("no files to distribute -- empty manifest?")
449
else:
450
log.info(msg)
451
for file in files:
452
if not os.path.isfile(file):
453
log.warn("'%s' not a regular file -- skipping", file)
454
else:
455
dest = os.path.join(base_dir, file)
456
self.copy_file(file, dest, link=link)
457
458
self.distribution.metadata.write_pkg_info(base_dir)
459
460
def make_distribution(self):
461
"""Create the source distribution(s). First, we create the release
462
tree with 'make_release_tree()'; then, we create all required
463
archive files (according to 'self.formats') from the release tree.
464
Finally, we clean up by blowing away the release tree (unless
465
'self.keep_temp' is true). The list of archive files created is
466
stored so it can be retrieved later by 'get_archive_files()'.
467
"""
468
# Don't warn about missing meta-data here -- should be (and is!)
469
# done elsewhere.
470
base_dir = self.distribution.get_fullname()
471
base_name = os.path.join(self.dist_dir, base_dir)
472
473
self.make_release_tree(base_dir, self.filelist.files)
474
archive_files = [] # remember names of files we create
475
# tar archive must be created last to avoid overwrite and remove
476
if 'tar' in self.formats:
477
self.formats.append(self.formats.pop(self.formats.index('tar')))
478
479
for fmt in self.formats:
480
file = self.make_archive(base_name, fmt, base_dir=base_dir,
481
owner=self.owner, group=self.group)
482
archive_files.append(file)
483
self.distribution.dist_files.append(('sdist', '', file))
484
485
self.archive_files = archive_files
486
487
if not self.keep_temp:
488
dir_util.remove_tree(base_dir, dry_run=self.dry_run)
489
490
def get_archive_files(self):
491
"""Return the list of archive files created when the command
492
was run, or None if the command hasn't run yet.
493
"""
494
return self.archive_files
495
496