Ignore:
Timestamp:
Mar 19, 2014, 11:31:01 PM (11 years ago)
Author:
dmik
Message:

python: Merge vendor 2.7.6 to trunk.

Location:
python/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • python/trunk

  • python/trunk/Lib/distutils/command/sdist.py

    r2 r391  
    33Implements the Distutils 'sdist' command (create a source distribution)."""
    44
    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
     7import os
     8import string
    109import sys
    11 from types import *
    1210from glob import glob
     11from warnings import warn
     12
    1313from distutils.core import Command
    1414from distutils import dir_util, dep_util, file_util, archive_util
    1515from distutils.text_file import TextFile
    16 from distutils.errors import *
     16from distutils.errors import (DistutilsPlatformError, DistutilsOptionError,
     17                              DistutilsTemplateError)
    1718from distutils.filelist import FileList
    1819from distutils import log
    19 
    20 
    21 def show_formats ():
     20from distutils.util import convert_path
     21
     22def show_formats():
    2223    """Print all possible values for the 'formats' option (used by
    2324    the "--help-formats" command-line option).
     
    2526    from distutils.fancy_getopt import FancyGetopt
    2627    from distutils.archive_util import ARCHIVE_FORMATS
    27     formats=[]
     28    formats = []
    2829    for format in ARCHIVE_FORMATS.keys():
    2930        formats.append(("formats=" + format, None,
    3031                        ARCHIVE_FORMATS[format][2]))
    3132    formats.sort()
    32     pretty_printer = FancyGetopt(formats)
    33     pretty_printer.print_help(
     33    FancyGetopt(formats).print_help(
    3434        "List of available source distribution formats:")
    3535
    36 class sdist (Command):
     36class sdist(Command):
    3737
    3838    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
    3945
    4046    user_options = [
     
    5864         "(implies --force-manifest)"),
    5965        ('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."),
    6168        ('formats=', None,
    6269         "formats for source distribution (comma-separated list)"),
     
    6774         "directory to put the source distribution archive(s) in "
    6875         "[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]"),
    6983        ]
    7084
    7185    boolean_options = ['use-defaults', 'prune',
    7286                       'manifest-only', 'force-manifest',
    73                        'keep-temp']
     87                       'keep-temp', 'metadata-check']
    7488
    7589    help_options = [
     
    8195                    'no-prune': 'prune' }
    8296
    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):
    87103        # 'template' and 'manifest' are, respectively, the names of
    88104        # the manifest template and manifest file.
     
    103119
    104120        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):
    108126        if self.manifest is None:
    109127            self.manifest = "MANIFEST"
     
    128146            self.dist_dir = "dist"
    129147
    130 
    131     def run (self):
    132 
     148    def run(self):
    133149        # 'filelist' contains the list of files that will make up the
    134150        # manifest
    135151        self.filelist = FileList()
    136152
    137         # Ensure that all required meta-data is given; warn if not (but
    138         # 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)
    140156
    141157        # Do whatever it takes to get the list of files to process
     
    152168        self.make_distribution()
    153169
    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):
    189179        """Figure out the list of files to include in the source
    190180        distribution, and put it in 'self.filelist'.  This might involve
    191181        reading the manifest template (and writing the manifest), or just
    192182        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.
    198192        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()
    247195            self.filelist.sort()
    248196            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):
    259219        """Add all the default files to self.filelist:
    260220          - README or README.txt
     
    262222          - test/test*.py
    263223          - 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.
    264227          - all C sources listed as part of extensions or C libraries
    265228            in the setup script (doesn't catch C headers!)
     
    270233        standards = [('README', 'README.txt'), self.distribution.script_name]
    271234        for fn in standards:
    272             if type(fn) is TupleType:
     235            if isinstance(fn, tuple):
    273236                alts = fn
    274237                got_it = 0
     
    294257                self.filelist.extend(files)
    295258
     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
    296265        if self.distribution.has_pure_modules():
    297             build_py = self.get_finalized_command('build_py')
    298266            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)
    299287
    300288        if self.distribution.has_ext_modules():
     
    310298            self.filelist.extend(build_scripts.get_source_files())
    311299
    312     # add_defaults ()
    313 
    314 
    315     def read_template (self):
     300    def read_template(self):
    316301        """Read and parse manifest template file named by self.template.
    317302
     
    328313                            collapse_join=1)
    329314
    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):
    346334        """Prune off branches that might slip into the file list as created
    347335        by 'read_template()', but really don't belong there:
     
    369357        self.filelist.exclude_pattern(vcs_ptrn, is_regex=1)
    370358
    371     def write_manifest (self):
     359    def write_manifest(self):
    372360        """Write the file list in 'self.filelist' (presumably as filled in
    373361        by 'add_defaults()' and 'read_template()') to the manifest file
    374362        named by 'self.manifest'.
    375363        """
    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),
    378372                     "writing manifest file '%s'" % self.manifest)
    379373
    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):
    384387        """Read the manifest file (named by 'self.manifest') and use it to
    385388        fill in 'self.filelist', the list of files to include in the source
     
    388391        log.info("reading manifest file '%s'", self.manifest)
    389392        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
    396398            self.filelist.append(line)
    397399        manifest.close()
    398400
    399     # read_manifest ()
    400 
    401 
    402     def make_release_tree (self, base_dir, files):
     401    def make_release_tree(self, base_dir, files):
    403402        """Create the directory tree that will become the source
    404403        distribution archive.  All directories implied by the filenames in
     
    442441        self.distribution.metadata.write_pkg_info(base_dir)
    443442
    444     # make_release_tree ()
    445 
    446     def make_distribution (self):
     443    def make_distribution(self):
    447444        """Create the source distribution(s).  First, we create the release
    448445        tree with 'make_release_tree()'; then, we create all required
     
    464461
    465462        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)
    467465            archive_files.append(file)
    468466            self.distribution.dist_files.append(('sdist', '', file))
     
    473471            dir_util.remove_tree(base_dir, dry_run=self.dry_run)
    474472
    475     def get_archive_files (self):
     473    def get_archive_files(self):
    476474        """Return the list of archive files created when the command
    477475        was run, or None if the command hasn't run yet.
    478476        """
    479477        return self.archive_files
    480 
    481 # class sdist
Note: See TracChangeset for help on using the changeset viewer.