symbian-qemu-0.9.1-12/python-win32-2.6.1/lib/distutils/command/sdist.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """distutils.command.sdist
       
     2 
       
     3 Implements the Distutils 'sdist' command (create a source distribution)."""
       
     4 
       
     5 # This module should be kept compatible with Python 2.1.
       
     6 
       
     7 __revision__ = "$Id: sdist.py 61263 2008-03-06 06:47:18Z georg.brandl $"
       
     8 
       
     9 import os, string
       
    10 from types import *
       
    11 from glob import glob
       
    12 from distutils.core import Command
       
    13 from distutils import dir_util, dep_util, file_util, archive_util
       
    14 from distutils.text_file import TextFile
       
    15 from distutils.errors import *
       
    16 from distutils.filelist import FileList
       
    17 from distutils import log
       
    18 
       
    19 
       
    20 def show_formats ():
       
    21     """Print all possible values for the 'formats' option (used by
       
    22     the "--help-formats" command-line option).
       
    23     """
       
    24     from distutils.fancy_getopt import FancyGetopt
       
    25     from distutils.archive_util import ARCHIVE_FORMATS
       
    26     formats=[]
       
    27     for format in ARCHIVE_FORMATS.keys():
       
    28         formats.append(("formats=" + format, None,
       
    29                         ARCHIVE_FORMATS[format][2]))
       
    30     formats.sort()
       
    31     pretty_printer = FancyGetopt(formats)
       
    32     pretty_printer.print_help(
       
    33         "List of available source distribution formats:")
       
    34 
       
    35 class sdist (Command):
       
    36 
       
    37     description = "create a source distribution (tarball, zip file, etc.)"
       
    38 
       
    39     user_options = [
       
    40         ('template=', 't',
       
    41          "name of manifest template file [default: MANIFEST.in]"),
       
    42         ('manifest=', 'm',
       
    43          "name of manifest file [default: MANIFEST]"),
       
    44         ('use-defaults', None,
       
    45          "include the default file set in the manifest "
       
    46          "[default; disable with --no-defaults]"),
       
    47         ('no-defaults', None,
       
    48          "don't include the default file set"),
       
    49         ('prune', None,
       
    50          "specifically exclude files/directories that should not be "
       
    51          "distributed (build tree, RCS/CVS dirs, etc.) "
       
    52          "[default; disable with --no-prune]"),
       
    53         ('no-prune', None,
       
    54          "don't automatically exclude anything"),
       
    55         ('manifest-only', 'o',
       
    56          "just regenerate the manifest and then stop "
       
    57          "(implies --force-manifest)"),
       
    58         ('force-manifest', 'f',
       
    59          "forcibly regenerate the manifest and carry on as usual"),
       
    60         ('formats=', None,
       
    61          "formats for source distribution (comma-separated list)"),
       
    62         ('keep-temp', 'k',
       
    63          "keep the distribution tree around after creating " +
       
    64          "archive file(s)"),
       
    65         ('dist-dir=', 'd',
       
    66          "directory to put the source distribution archive(s) in "
       
    67          "[default: dist]"),
       
    68         ]
       
    69 
       
    70     boolean_options = ['use-defaults', 'prune',
       
    71                        'manifest-only', 'force-manifest',
       
    72                        'keep-temp']
       
    73 
       
    74     help_options = [
       
    75         ('help-formats', None,
       
    76          "list available distribution formats", show_formats),
       
    77         ]
       
    78 
       
    79     negative_opt = {'no-defaults': 'use-defaults',
       
    80                     'no-prune': 'prune' }
       
    81 
       
    82     default_format = { 'posix': 'gztar',
       
    83                        'nt': 'zip' }
       
    84 
       
    85     def initialize_options (self):
       
    86         # 'template' and 'manifest' are, respectively, the names of
       
    87         # the manifest template and manifest file.
       
    88         self.template = None
       
    89         self.manifest = None
       
    90 
       
    91         # 'use_defaults': if true, we will include the default file set
       
    92         # in the manifest
       
    93         self.use_defaults = 1
       
    94         self.prune = 1
       
    95 
       
    96         self.manifest_only = 0
       
    97         self.force_manifest = 0
       
    98 
       
    99         self.formats = None
       
   100         self.keep_temp = 0
       
   101         self.dist_dir = None
       
   102 
       
   103         self.archive_files = None
       
   104 
       
   105 
       
   106     def finalize_options (self):
       
   107         if self.manifest is None:
       
   108             self.manifest = "MANIFEST"
       
   109         if self.template is None:
       
   110             self.template = "MANIFEST.in"
       
   111 
       
   112         self.ensure_string_list('formats')
       
   113         if self.formats is None:
       
   114             try:
       
   115                 self.formats = [self.default_format[os.name]]
       
   116             except KeyError:
       
   117                 raise DistutilsPlatformError, \
       
   118                       "don't know how to create source distributions " + \
       
   119                       "on platform %s" % os.name
       
   120 
       
   121         bad_format = archive_util.check_archive_formats(self.formats)
       
   122         if bad_format:
       
   123             raise DistutilsOptionError, \
       
   124                   "unknown archive format '%s'" % bad_format
       
   125 
       
   126         if self.dist_dir is None:
       
   127             self.dist_dir = "dist"
       
   128 
       
   129 
       
   130     def run (self):
       
   131 
       
   132         # 'filelist' contains the list of files that will make up the
       
   133         # manifest
       
   134         self.filelist = FileList()
       
   135 
       
   136         # Ensure that all required meta-data is given; warn if not (but
       
   137         # don't die, it's not *that* serious!)
       
   138         self.check_metadata()
       
   139 
       
   140         # Do whatever it takes to get the list of files to process
       
   141         # (process the manifest template, read an existing manifest,
       
   142         # whatever).  File list is accumulated in 'self.filelist'.
       
   143         self.get_file_list()
       
   144 
       
   145         # If user just wanted us to regenerate the manifest, stop now.
       
   146         if self.manifest_only:
       
   147             return
       
   148 
       
   149         # Otherwise, go ahead and create the source distribution tarball,
       
   150         # or zipfile, or whatever.
       
   151         self.make_distribution()
       
   152 
       
   153 
       
   154     def check_metadata (self):
       
   155         """Ensure that all required elements of meta-data (name, version,
       
   156         URL, (author and author_email) or (maintainer and
       
   157         maintainer_email)) are supplied by the Distribution object; warn if
       
   158         any are missing.
       
   159         """
       
   160         metadata = self.distribution.metadata
       
   161 
       
   162         missing = []
       
   163         for attr in ('name', 'version', 'url'):
       
   164             if not (hasattr(metadata, attr) and getattr(metadata, attr)):
       
   165                 missing.append(attr)
       
   166 
       
   167         if missing:
       
   168             self.warn("missing required meta-data: " +
       
   169                       string.join(missing, ", "))
       
   170 
       
   171         if metadata.author:
       
   172             if not metadata.author_email:
       
   173                 self.warn("missing meta-data: if 'author' supplied, " +
       
   174                           "'author_email' must be supplied too")
       
   175         elif metadata.maintainer:
       
   176             if not metadata.maintainer_email:
       
   177                 self.warn("missing meta-data: if 'maintainer' supplied, " +
       
   178                           "'maintainer_email' must be supplied too")
       
   179         else:
       
   180             self.warn("missing meta-data: either (author and author_email) " +
       
   181                       "or (maintainer and maintainer_email) " +
       
   182                       "must be supplied")
       
   183 
       
   184     # check_metadata ()
       
   185 
       
   186 
       
   187     def get_file_list (self):
       
   188         """Figure out the list of files to include in the source
       
   189         distribution, and put it in 'self.filelist'.  This might involve
       
   190         reading the manifest template (and writing the manifest), or just
       
   191         reading the manifest, or just using the default file set -- it all
       
   192         depends on the user's options and the state of the filesystem.
       
   193         """
       
   194 
       
   195         # If we have a manifest template, see if it's newer than the
       
   196         # manifest; if so, we'll regenerate the manifest.
       
   197         template_exists = os.path.isfile(self.template)
       
   198         if template_exists:
       
   199             template_newer = dep_util.newer(self.template, self.manifest)
       
   200 
       
   201         # The contents of the manifest file almost certainly depend on the
       
   202         # setup script as well as the manifest template -- so if the setup
       
   203         # script is newer than the manifest, we'll regenerate the manifest
       
   204         # from the template.  (Well, not quite: if we already have a
       
   205         # manifest, but there's no template -- which will happen if the
       
   206         # developer elects to generate a manifest some other way -- then we
       
   207         # can't regenerate the manifest, so we don't.)
       
   208         self.debug_print("checking if %s newer than %s" %
       
   209                          (self.distribution.script_name, self.manifest))
       
   210         setup_newer = dep_util.newer(self.distribution.script_name,
       
   211                                      self.manifest)
       
   212 
       
   213         # cases:
       
   214         #   1) no manifest, template exists: generate manifest
       
   215         #      (covered by 2a: no manifest == template newer)
       
   216         #   2) manifest & template exist:
       
   217         #      2a) template or setup script newer than manifest:
       
   218         #          regenerate manifest
       
   219         #      2b) manifest newer than both:
       
   220         #          do nothing (unless --force or --manifest-only)
       
   221         #   3) manifest exists, no template:
       
   222         #      do nothing (unless --force or --manifest-only)
       
   223         #   4) no manifest, no template: generate w/ warning ("defaults only")
       
   224 
       
   225         manifest_outofdate = (template_exists and
       
   226                               (template_newer or setup_newer))
       
   227         force_regen = self.force_manifest or self.manifest_only
       
   228         manifest_exists = os.path.isfile(self.manifest)
       
   229         neither_exists = (not template_exists and not manifest_exists)
       
   230 
       
   231         # Regenerate the manifest if necessary (or if explicitly told to)
       
   232         if manifest_outofdate or neither_exists or force_regen:
       
   233             if not template_exists:
       
   234                 self.warn(("manifest template '%s' does not exist " +
       
   235                            "(using default file list)") %
       
   236                           self.template)
       
   237             self.filelist.findall()
       
   238 
       
   239             if self.use_defaults:
       
   240                 self.add_defaults()
       
   241             if template_exists:
       
   242                 self.read_template()
       
   243             if self.prune:
       
   244                 self.prune_file_list()
       
   245 
       
   246             self.filelist.sort()
       
   247             self.filelist.remove_duplicates()
       
   248             self.write_manifest()
       
   249 
       
   250         # Don't regenerate the manifest, just read it in.
       
   251         else:
       
   252             self.read_manifest()
       
   253 
       
   254     # get_file_list ()
       
   255 
       
   256 
       
   257     def add_defaults (self):
       
   258         """Add all the default files to self.filelist:
       
   259           - README or README.txt
       
   260           - setup.py
       
   261           - test/test*.py
       
   262           - all pure Python modules mentioned in setup script
       
   263           - all C sources listed as part of extensions or C libraries
       
   264             in the setup script (doesn't catch C headers!)
       
   265         Warns if (README or README.txt) or setup.py are missing; everything
       
   266         else is optional.
       
   267         """
       
   268 
       
   269         standards = [('README', 'README.txt'), self.distribution.script_name]
       
   270         for fn in standards:
       
   271             if type(fn) is TupleType:
       
   272                 alts = fn
       
   273                 got_it = 0
       
   274                 for fn in alts:
       
   275                     if os.path.exists(fn):
       
   276                         got_it = 1
       
   277                         self.filelist.append(fn)
       
   278                         break
       
   279 
       
   280                 if not got_it:
       
   281                     self.warn("standard file not found: should have one of " +
       
   282                               string.join(alts, ', '))
       
   283             else:
       
   284                 if os.path.exists(fn):
       
   285                     self.filelist.append(fn)
       
   286                 else:
       
   287                     self.warn("standard file '%s' not found" % fn)
       
   288 
       
   289         optional = ['test/test*.py', 'setup.cfg']
       
   290         for pattern in optional:
       
   291             files = filter(os.path.isfile, glob(pattern))
       
   292             if files:
       
   293                 self.filelist.extend(files)
       
   294 
       
   295         if self.distribution.has_pure_modules():
       
   296             build_py = self.get_finalized_command('build_py')
       
   297             self.filelist.extend(build_py.get_source_files())
       
   298 
       
   299         if self.distribution.has_ext_modules():
       
   300             build_ext = self.get_finalized_command('build_ext')
       
   301             self.filelist.extend(build_ext.get_source_files())
       
   302 
       
   303         if self.distribution.has_c_libraries():
       
   304             build_clib = self.get_finalized_command('build_clib')
       
   305             self.filelist.extend(build_clib.get_source_files())
       
   306 
       
   307         if self.distribution.has_scripts():
       
   308             build_scripts = self.get_finalized_command('build_scripts')
       
   309             self.filelist.extend(build_scripts.get_source_files())
       
   310 
       
   311     # add_defaults ()
       
   312 
       
   313 
       
   314     def read_template (self):
       
   315         """Read and parse manifest template file named by self.template.
       
   316 
       
   317         (usually "MANIFEST.in") The parsing and processing is done by
       
   318         'self.filelist', which updates itself accordingly.
       
   319         """
       
   320         log.info("reading manifest template '%s'", self.template)
       
   321         template = TextFile(self.template,
       
   322                             strip_comments=1,
       
   323                             skip_blanks=1,
       
   324                             join_lines=1,
       
   325                             lstrip_ws=1,
       
   326                             rstrip_ws=1,
       
   327                             collapse_join=1)
       
   328 
       
   329         while 1:
       
   330             line = template.readline()
       
   331             if line is None:            # end of file
       
   332                 break
       
   333 
       
   334             try:
       
   335                 self.filelist.process_template_line(line)
       
   336             except DistutilsTemplateError, msg:
       
   337                 self.warn("%s, line %d: %s" % (template.filename,
       
   338                                                template.current_line,
       
   339                                                msg))
       
   340 
       
   341     # read_template ()
       
   342 
       
   343 
       
   344     def prune_file_list (self):
       
   345         """Prune off branches that might slip into the file list as created
       
   346         by 'read_template()', but really don't belong there:
       
   347           * the build tree (typically "build")
       
   348           * the release tree itself (only an issue if we ran "sdist"
       
   349             previously with --keep-temp, or it aborted)
       
   350           * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories
       
   351         """
       
   352         build = self.get_finalized_command('build')
       
   353         base_dir = self.distribution.get_fullname()
       
   354 
       
   355         self.filelist.exclude_pattern(None, prefix=build.build_base)
       
   356         self.filelist.exclude_pattern(None, prefix=base_dir)
       
   357         self.filelist.exclude_pattern(r'(^|/)(RCS|CVS|\.svn|\.hg|\.git|\.bzr|_darcs)/.*', is_regex=1)
       
   358 
       
   359 
       
   360     def write_manifest (self):
       
   361         """Write the file list in 'self.filelist' (presumably as filled in
       
   362         by 'add_defaults()' and 'read_template()') to the manifest file
       
   363         named by 'self.manifest'.
       
   364         """
       
   365         self.execute(file_util.write_file,
       
   366                      (self.manifest, self.filelist.files),
       
   367                      "writing manifest file '%s'" % self.manifest)
       
   368 
       
   369     # write_manifest ()
       
   370 
       
   371 
       
   372     def read_manifest (self):
       
   373         """Read the manifest file (named by 'self.manifest') and use it to
       
   374         fill in 'self.filelist', the list of files to include in the source
       
   375         distribution.
       
   376         """
       
   377         log.info("reading manifest file '%s'", self.manifest)
       
   378         manifest = open(self.manifest)
       
   379         while 1:
       
   380             line = manifest.readline()
       
   381             if line == '':              # end of file
       
   382                 break
       
   383             if line[-1] == '\n':
       
   384                 line = line[0:-1]
       
   385             self.filelist.append(line)
       
   386         manifest.close()
       
   387 
       
   388     # read_manifest ()
       
   389 
       
   390 
       
   391     def make_release_tree (self, base_dir, files):
       
   392         """Create the directory tree that will become the source
       
   393         distribution archive.  All directories implied by the filenames in
       
   394         'files' are created under 'base_dir', and then we hard link or copy
       
   395         (if hard linking is unavailable) those files into place.
       
   396         Essentially, this duplicates the developer's source tree, but in a
       
   397         directory named after the distribution, containing only the files
       
   398         to be distributed.
       
   399         """
       
   400         # Create all the directories under 'base_dir' necessary to
       
   401         # put 'files' there; the 'mkpath()' is just so we don't die
       
   402         # if the manifest happens to be empty.
       
   403         self.mkpath(base_dir)
       
   404         dir_util.create_tree(base_dir, files, dry_run=self.dry_run)
       
   405 
       
   406         # And walk over the list of files, either making a hard link (if
       
   407         # os.link exists) to each one that doesn't already exist in its
       
   408         # corresponding location under 'base_dir', or copying each file
       
   409         # that's out-of-date in 'base_dir'.  (Usually, all files will be
       
   410         # out-of-date, because by default we blow away 'base_dir' when
       
   411         # we're done making the distribution archives.)
       
   412 
       
   413         if hasattr(os, 'link'):        # can make hard links on this system
       
   414             link = 'hard'
       
   415             msg = "making hard links in %s..." % base_dir
       
   416         else:                           # nope, have to copy
       
   417             link = None
       
   418             msg = "copying files to %s..." % base_dir
       
   419 
       
   420         if not files:
       
   421             log.warn("no files to distribute -- empty manifest?")
       
   422         else:
       
   423             log.info(msg)
       
   424         for file in files:
       
   425             if not os.path.isfile(file):
       
   426                 log.warn("'%s' not a regular file -- skipping" % file)
       
   427             else:
       
   428                 dest = os.path.join(base_dir, file)
       
   429                 self.copy_file(file, dest, link=link)
       
   430 
       
   431         self.distribution.metadata.write_pkg_info(base_dir)
       
   432 
       
   433     # make_release_tree ()
       
   434 
       
   435     def make_distribution (self):
       
   436         """Create the source distribution(s).  First, we create the release
       
   437         tree with 'make_release_tree()'; then, we create all required
       
   438         archive files (according to 'self.formats') from the release tree.
       
   439         Finally, we clean up by blowing away the release tree (unless
       
   440         'self.keep_temp' is true).  The list of archive files created is
       
   441         stored so it can be retrieved later by 'get_archive_files()'.
       
   442         """
       
   443         # Don't warn about missing meta-data here -- should be (and is!)
       
   444         # done elsewhere.
       
   445         base_dir = self.distribution.get_fullname()
       
   446         base_name = os.path.join(self.dist_dir, base_dir)
       
   447 
       
   448         self.make_release_tree(base_dir, self.filelist.files)
       
   449         archive_files = []              # remember names of files we create
       
   450         for fmt in self.formats:
       
   451             file = self.make_archive(base_name, fmt, base_dir=base_dir)
       
   452             archive_files.append(file)
       
   453             self.distribution.dist_files.append(('sdist', '', file))
       
   454 
       
   455         self.archive_files = archive_files
       
   456 
       
   457         if not self.keep_temp:
       
   458             dir_util.remove_tree(base_dir, dry_run=self.dry_run)
       
   459 
       
   460     def get_archive_files (self):
       
   461         """Return the list of archive files created when the command
       
   462         was run, or None if the command hasn't run yet.
       
   463         """
       
   464         return self.archive_files
       
   465 
       
   466 # class sdist