Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/setuptools/_distutils/command/sdist.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
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 |