Changeset 391 for python/trunk/Lib/distutils/command/sdist.py
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
python/trunk/Lib/distutils/command/sdist.py
r2 r391 3 3 Implements the Distutils 'sdist' command (create a source distribution).""" 4 4 5 # This module should be kept compatible with Python 2.1. 6 7 __revision__ = "$Id: sdist.py 68968 2009-01-26 17:20:15Z tarek.ziade $" 8 9 import os, string 5 __revision__ = "$Id$" 6 7 import os 8 import string 10 9 import sys 11 from types import *12 10 from glob import glob 11 from warnings import warn 12 13 13 from distutils.core import Command 14 14 from distutils import dir_util, dep_util, file_util, archive_util 15 15 from distutils.text_file import TextFile 16 from distutils.errors import * 16 from distutils.errors import (DistutilsPlatformError, DistutilsOptionError, 17 DistutilsTemplateError) 17 18 from distutils.filelist import FileList 18 19 from distutils import log 19 20 21 def show_formats 20 from distutils.util import convert_path 21 22 def show_formats(): 22 23 """Print all possible values for the 'formats' option (used by 23 24 the "--help-formats" command-line option). … … 25 26 from distutils.fancy_getopt import FancyGetopt 26 27 from distutils.archive_util import ARCHIVE_FORMATS 27 formats =[]28 formats = [] 28 29 for format in ARCHIVE_FORMATS.keys(): 29 30 formats.append(("formats=" + format, None, 30 31 ARCHIVE_FORMATS[format][2])) 31 32 formats.sort() 32 pretty_printer = FancyGetopt(formats) 33 pretty_printer.print_help( 33 FancyGetopt(formats).print_help( 34 34 "List of available source distribution formats:") 35 35 36 class sdist 36 class sdist(Command): 37 37 38 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 39 45 40 46 user_options = [ … … 58 64 "(implies --force-manifest)"), 59 65 ('force-manifest', 'f', 60 "forcibly regenerate the manifest and carry on as usual"), 66 "forcibly regenerate the manifest and carry on as usual. " 67 "Deprecated: now the manifest is always regenerated."), 61 68 ('formats=', None, 62 69 "formats for source distribution (comma-separated list)"), … … 67 74 "directory to put the source distribution archive(s) in " 68 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]"), 69 83 ] 70 84 71 85 boolean_options = ['use-defaults', 'prune', 72 86 'manifest-only', 'force-manifest', 73 'keep-temp' ]87 'keep-temp', 'metadata-check'] 74 88 75 89 help_options = [ … … 81 95 'no-prune': 'prune' } 82 96 83 default_format = { 'posix': 'gztar', 84 'nt': 'zip' } 85 86 def initialize_options (self): 97 default_format = {'posix': 'gztar', 98 'nt': 'zip' } 99 100 sub_commands = [('check', checking_metadata)] 101 102 def initialize_options(self): 87 103 # 'template' and 'manifest' are, respectively, the names of 88 104 # the manifest template and manifest file. … … 103 119 104 120 self.archive_files = None 105 106 107 def finalize_options (self): 121 self.metadata_check = 1 122 self.owner = None 123 self.group = None 124 125 def finalize_options(self): 108 126 if self.manifest is None: 109 127 self.manifest = "MANIFEST" … … 128 146 self.dist_dir = "dist" 129 147 130 131 def run (self): 132 148 def run(self): 133 149 # 'filelist' contains the list of files that will make up the 134 150 # manifest 135 151 self.filelist = FileList() 136 152 137 # Ensure that all required meta-data is given; warn if not (but138 # don't die, it's not *that* serious!)139 self.check_metadata()153 # Run sub commands 154 for cmd_name in self.get_sub_commands(): 155 self.run_command(cmd_name) 140 156 141 157 # Do whatever it takes to get the list of files to process … … 152 168 self.make_distribution() 153 169 154 155 def check_metadata (self): 156 """Ensure that all required elements of meta-data (name, version, 157 URL, (author and author_email) or (maintainer and 158 maintainer_email)) are supplied by the Distribution object; warn if 159 any are missing. 160 """ 161 metadata = self.distribution.metadata 162 163 missing = [] 164 for attr in ('name', 'version', 'url'): 165 if not (hasattr(metadata, attr) and getattr(metadata, attr)): 166 missing.append(attr) 167 168 if missing: 169 self.warn("missing required meta-data: " + 170 string.join(missing, ", ")) 171 172 if metadata.author: 173 if not metadata.author_email: 174 self.warn("missing meta-data: if 'author' supplied, " + 175 "'author_email' must be supplied too") 176 elif metadata.maintainer: 177 if not metadata.maintainer_email: 178 self.warn("missing meta-data: if 'maintainer' supplied, " + 179 "'maintainer_email' must be supplied too") 180 else: 181 self.warn("missing meta-data: either (author and author_email) " + 182 "or (maintainer and maintainer_email) " + 183 "must be supplied") 184 185 # check_metadata () 186 187 188 def get_file_list (self): 170 def check_metadata(self): 171 """Deprecated API.""" 172 warn("distutils.command.sdist.check_metadata is deprecated, \ 173 use the check command instead", PendingDeprecationWarning) 174 check = self.distribution.get_command_obj('check') 175 check.ensure_finalized() 176 check.run() 177 178 def get_file_list(self): 189 179 """Figure out the list of files to include in the source 190 180 distribution, and put it in 'self.filelist'. This might involve 191 181 reading the manifest template (and writing the manifest), or just 192 182 reading the manifest, or just using the default file set -- it all 193 depends on the user's options and the state of the filesystem. 194 """ 195 196 # If we have a manifest template, see if it's newer than the 197 # manifest; if so, we'll regenerate the manifest. 183 depends on the user's options. 184 """ 185 # new behavior when using a template: 186 # the file list is recalculated every time because 187 # even if MANIFEST.in or setup.py are not changed 188 # the user might have added some files in the tree that 189 # need to be included. 190 # 191 # This makes --force the default and only behavior with templates. 198 192 template_exists = os.path.isfile(self.template) 199 if template_exists: 200 template_newer = dep_util.newer(self.template, self.manifest) 201 202 # The contents of the manifest file almost certainly depend on the 203 # setup script as well as the manifest template -- so if the setup 204 # script is newer than the manifest, we'll regenerate the manifest 205 # from the template. (Well, not quite: if we already have a 206 # manifest, but there's no template -- which will happen if the 207 # developer elects to generate a manifest some other way -- then we 208 # can't regenerate the manifest, so we don't.) 209 self.debug_print("checking if %s newer than %s" % 210 (self.distribution.script_name, self.manifest)) 211 setup_newer = dep_util.newer(self.distribution.script_name, 212 self.manifest) 213 214 # cases: 215 # 1) no manifest, template exists: generate manifest 216 # (covered by 2a: no manifest == template newer) 217 # 2) manifest & template exist: 218 # 2a) template or setup script newer than manifest: 219 # regenerate manifest 220 # 2b) manifest newer than both: 221 # do nothing (unless --force or --manifest-only) 222 # 3) manifest exists, no template: 223 # do nothing (unless --force or --manifest-only) 224 # 4) no manifest, no template: generate w/ warning ("defaults only") 225 226 manifest_outofdate = (template_exists and 227 (template_newer or setup_newer)) 228 force_regen = self.force_manifest or self.manifest_only 229 manifest_exists = os.path.isfile(self.manifest) 230 neither_exists = (not template_exists and not manifest_exists) 231 232 # Regenerate the manifest if necessary (or if explicitly told to) 233 if manifest_outofdate or neither_exists or force_regen: 234 if not template_exists: 235 self.warn(("manifest template '%s' does not exist " + 236 "(using default file list)") % 237 self.template) 238 self.filelist.findall() 239 240 if self.use_defaults: 241 self.add_defaults() 242 if template_exists: 243 self.read_template() 244 if self.prune: 245 self.prune_file_list() 246 193 if not template_exists and self._manifest_is_not_generated(): 194 self.read_manifest() 247 195 self.filelist.sort() 248 196 self.filelist.remove_duplicates() 249 self.write_manifest() 250 251 # Don't regenerate the manifest, just read it in. 252 else: 253 self.read_manifest() 254 255 # get_file_list () 256 257 258 def add_defaults (self): 197 return 198 199 if not template_exists: 200 self.warn(("manifest template '%s' does not exist " + 201 "(using default file list)") % 202 self.template) 203 self.filelist.findall() 204 205 if self.use_defaults: 206 self.add_defaults() 207 208 if template_exists: 209 self.read_template() 210 211 if self.prune: 212 self.prune_file_list() 213 214 self.filelist.sort() 215 self.filelist.remove_duplicates() 216 self.write_manifest() 217 218 def add_defaults(self): 259 219 """Add all the default files to self.filelist: 260 220 - README or README.txt … … 262 222 - test/test*.py 263 223 - all pure Python modules mentioned in setup script 224 - all files pointed by package_data (build_py) 225 - all files defined in data_files. 226 - all files defined as scripts. 264 227 - all C sources listed as part of extensions or C libraries 265 228 in the setup script (doesn't catch C headers!) … … 270 233 standards = [('README', 'README.txt'), self.distribution.script_name] 271 234 for fn in standards: 272 if type(fn) is TupleType:235 if isinstance(fn, tuple): 273 236 alts = fn 274 237 got_it = 0 … … 294 257 self.filelist.extend(files) 295 258 259 # build_py is used to get: 260 # - python modules 261 # - files defined in package_data 262 build_py = self.get_finalized_command('build_py') 263 264 # getting python files 296 265 if self.distribution.has_pure_modules(): 297 build_py = self.get_finalized_command('build_py')298 266 self.filelist.extend(build_py.get_source_files()) 267 268 # getting package_data files 269 # (computed in build_py.data_files by build_py.finalize_options) 270 for pkg, src_dir, build_dir, filenames in build_py.data_files: 271 for filename in filenames: 272 self.filelist.append(os.path.join(src_dir, filename)) 273 274 # getting distribution.data_files 275 if self.distribution.has_data_files(): 276 for item in self.distribution.data_files: 277 if isinstance(item, str): # plain file 278 item = convert_path(item) 279 if os.path.isfile(item): 280 self.filelist.append(item) 281 else: # a (dirname, filenames) tuple 282 dirname, filenames = item 283 for f in filenames: 284 f = convert_path(f) 285 if os.path.isfile(f): 286 self.filelist.append(f) 299 287 300 288 if self.distribution.has_ext_modules(): … … 310 298 self.filelist.extend(build_scripts.get_source_files()) 311 299 312 # add_defaults () 313 314 315 def read_template (self): 300 def read_template(self): 316 301 """Read and parse manifest template file named by self.template. 317 302 … … 328 313 collapse_join=1) 329 314 330 while 1: 331 line = template.readline() 332 if line is None: # end of file 333 break 334 335 try: 336 self.filelist.process_template_line(line) 337 except DistutilsTemplateError, msg: 338 self.warn("%s, line %d: %s" % (template.filename, 339 template.current_line, 340 msg)) 341 342 # read_template () 343 344 345 def prune_file_list (self): 315 try: 316 while 1: 317 line = template.readline() 318 if line is None: # end of file 319 break 320 321 try: 322 self.filelist.process_template_line(line) 323 # the call above can raise a DistutilsTemplateError for 324 # malformed lines, or a ValueError from the lower-level 325 # convert_path function 326 except (DistutilsTemplateError, ValueError) as msg: 327 self.warn("%s, line %d: %s" % (template.filename, 328 template.current_line, 329 msg)) 330 finally: 331 template.close() 332 333 def prune_file_list(self): 346 334 """Prune off branches that might slip into the file list as created 347 335 by 'read_template()', but really don't belong there: … … 369 357 self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) 370 358 371 def write_manifest 359 def write_manifest(self): 372 360 """Write the file list in 'self.filelist' (presumably as filled in 373 361 by 'add_defaults()' and 'read_template()') to the manifest file 374 362 named by 'self.manifest'. 375 363 """ 376 self.execute(file_util.write_file, 377 (self.manifest, self.filelist.files), 364 if self._manifest_is_not_generated(): 365 log.info("not writing to manually maintained " 366 "manifest file '%s'" % self.manifest) 367 return 368 369 content = self.filelist.files[:] 370 content.insert(0, '# file GENERATED by distutils, do NOT edit') 371 self.execute(file_util.write_file, (self.manifest, content), 378 372 "writing manifest file '%s'" % self.manifest) 379 373 380 # write_manifest () 381 382 383 def read_manifest (self): 374 def _manifest_is_not_generated(self): 375 # check for special comment used in 2.7.1 and higher 376 if not os.path.isfile(self.manifest): 377 return False 378 379 fp = open(self.manifest, 'rU') 380 try: 381 first_line = fp.readline() 382 finally: 383 fp.close() 384 return first_line != '# file GENERATED by distutils, do NOT edit\n' 385 386 def read_manifest(self): 384 387 """Read the manifest file (named by 'self.manifest') and use it to 385 388 fill in 'self.filelist', the list of files to include in the source … … 388 391 log.info("reading manifest file '%s'", self.manifest) 389 392 manifest = open(self.manifest) 390 while 1: 391 line = manifest.readline() 392 if line == '': # end of file 393 break 394 if line[-1] == '\n': 395 line = line[0:-1] 393 for line in manifest: 394 # ignore comments and blank lines 395 line = line.strip() 396 if line.startswith('#') or not line: 397 continue 396 398 self.filelist.append(line) 397 399 manifest.close() 398 400 399 # read_manifest () 400 401 402 def make_release_tree (self, base_dir, files): 401 def make_release_tree(self, base_dir, files): 403 402 """Create the directory tree that will become the source 404 403 distribution archive. All directories implied by the filenames in … … 442 441 self.distribution.metadata.write_pkg_info(base_dir) 443 442 444 # make_release_tree () 445 446 def make_distribution (self): 443 def make_distribution(self): 447 444 """Create the source distribution(s). First, we create the release 448 445 tree with 'make_release_tree()'; then, we create all required … … 464 461 465 462 for fmt in self.formats: 466 file = self.make_archive(base_name, fmt, base_dir=base_dir) 463 file = self.make_archive(base_name, fmt, base_dir=base_dir, 464 owner=self.owner, group=self.group) 467 465 archive_files.append(file) 468 466 self.distribution.dist_files.append(('sdist', '', file)) … … 473 471 dir_util.remove_tree(base_dir, dry_run=self.dry_run) 474 472 475 def get_archive_files 473 def get_archive_files(self): 476 474 """Return the list of archive files created when the command 477 475 was run, or None if the command hasn't run yet. 478 476 """ 479 477 return self.archive_files 480 481 # class sdist
Note:
See TracChangeset
for help on using the changeset viewer.