]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/command/sdist.py
   1 """distutils.command.sdist 
   3 Implements the Distutils 'sdist' command (create a source distribution).""" 
   5 # This module should be kept compatible with Python 1.5.2. 
  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
 
  21     """Print all possible values for the 'formats' option (used by 
  22     the "--help-formats" command-line option). 
  24     from distutils
.fancy_getopt 
import FancyGetopt
 
  25     from distutils
.archive_util 
import ARCHIVE_FORMATS
 
  27     for format 
in ARCHIVE_FORMATS
.keys(): 
  28         formats
.append(("formats=" + format
, None, 
  29                         ARCHIVE_FORMATS
[format
][2])) 
  31     pretty_printer 
= FancyGetopt(formats
) 
  32     pretty_printer
.print_help( 
  33         "List of available source distribution formats:") 
  35 class sdist (Command
): 
  37     description 
= "create a source distribution (tarball, zip file, etc.)" 
  41          "name of manifest template file [default: MANIFEST.in]"), 
  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]"), 
  48          "don't include the default file set"), 
  50          "specifically exclude files/directories that should not be " 
  51          "distributed (build tree, RCS/CVS dirs, etc.) " 
  52          "[default; disable with --no-prune]"), 
  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"), 
  61          "formats for source distribution (comma-separated list)"), 
  63          "keep the distribution tree around after creating " + 
  66          "directory to put the source distribution archive(s) in " 
  70     boolean_options 
= ['use-defaults', 'prune', 
  71                        'manifest-only', 'force-manifest', 
  75         ('help-formats', None, 
  76          "list available distribution formats", show_formats
), 
  79     negative_opt 
= {'no-defaults': 'use-defaults', 
  82     default_format 
= { 'posix': 'gztar', 
  85     def initialize_options (self
): 
  86         # 'template' and 'manifest' are, respectively, the names of 
  87         # the manifest template and manifest file. 
  91         # 'use_defaults': if true, we will include the default file set 
  96         self
.manifest_only 
= 0 
  97         self
.force_manifest 
= 0 
 103         self
.archive_files 
= None 
 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" 
 112         self
.ensure_string_list('formats') 
 113         if self
.formats 
is None: 
 115                 self
.formats 
= [self
.default_format
[os
.name
]] 
 117                 raise DistutilsPlatformError
, \
 
 118                       "don't know how to create source distributions " + \
 
 119                       "on platform %s" % os
.name
 
 121         bad_format 
= archive_util
.check_archive_formats(self
.formats
) 
 123             raise DistutilsOptionError
, \
 
 124                   "unknown archive format '%s'" % bad_format
 
 126         if self
.dist_dir 
is None: 
 127             self
.dist_dir 
= "dist" 
 132         # 'filelist' contains the list of files that will make up the 
 134         self
.filelist 
= FileList() 
 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() 
 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'. 
 145         # If user just wanted us to regenerate the manifest, stop now. 
 146         if self
.manifest_only
: 
 149         # Otherwise, go ahead and create the source distribution tarball, 
 150         # or zipfile, or whatever. 
 151         self
.make_distribution() 
 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 
 160         metadata 
= self
.distribution
.metadata
 
 163         for attr 
in ('name', 'version', 'url'): 
 164             if not (hasattr(metadata
, attr
) and getattr(metadata
, attr
)): 
 168             self
.warn("missing required meta-data: " + 
 169                       string
.join(missing
, ", ")) 
 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") 
 180             self
.warn("missing meta-data: either (author and author_email) " + 
 181                       "or (maintainer and maintainer_email) " + 
 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. 
 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
) 
 199             template_newer 
= dep_util
.newer(self
.template
, self
.manifest
) 
 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
, 
 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") 
 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
) 
 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)") % 
 237             self
.filelist
.findall() 
 239             if self
.use_defaults
: 
 244                 self
.prune_file_list() 
 247             self
.filelist
.remove_duplicates() 
 248             self
.write_manifest() 
 250         # Don't regenerate the manifest, just read it in. 
 257     def add_defaults (self
): 
 258         """Add all the default files to self.filelist: 
 259           - README or README.txt 
 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 
 269         standards 
= [('README', 'README.txt'), self
.distribution
.script_name
] 
 271             if type(fn
) is TupleType
: 
 275                     if os
.path
.exists(fn
): 
 277                         self
.filelist
.append(fn
) 
 281                     self
.warn("standard file not found: should have one of " + 
 282                               string
.join(alts
, ', ')) 
 284                 if os
.path
.exists(fn
): 
 285                     self
.filelist
.append(fn
) 
 287                     self
.warn("standard file '%s' not found" % fn
) 
 289         optional 
= ['test/test*.py', 'setup.cfg'] 
 290         for pattern 
in optional
: 
 291             files 
= filter(os
.path
.isfile
, glob(pattern
)) 
 293                 self
.filelist
.extend(files
) 
 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()) 
 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()) 
 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()) 
 310     def read_template (self
): 
 311         """Read and parse manifest template file named by self.template. 
 313         (usually "MANIFEST.in") The parsing and processing is done by 
 314         'self.filelist', which updates itself accordingly. 
 316         log
.info("reading manifest template '%s'", self
.template
) 
 317         template 
= TextFile(self
.template
, 
 326             line 
= template
.readline() 
 327             if line 
is None:            # end of file 
 331                 self
.filelist
.process_template_line(line
) 
 332             except DistutilsTemplateError
, msg
: 
 333                 self
.warn("%s, line %d: %s" % (template
.filename
, 
 334                                                template
.current_line
, 
 340     def prune_file_list (self
): 
 341         """Prune off branches that might slip into the file list as created 
 342         by 'read_template()', but really don't belong there: 
 343           * the build tree (typically "build") 
 344           * the release tree itself (only an issue if we ran "sdist" 
 345             previously with --keep-temp, or it aborted) 
 346           * any RCS or CVS directories 
 348         build 
= self
.get_finalized_command('build') 
 349         base_dir 
= self
.distribution
.get_fullname() 
 351         self
.filelist
.exclude_pattern(None, prefix
=build
.build_base
) 
 352         self
.filelist
.exclude_pattern(None, prefix
=base_dir
) 
 353         self
.filelist
.exclude_pattern(r
'/(RCS|CVS)/.*', is_regex
=1) 
 356     def write_manifest (self
): 
 357         """Write the file list in 'self.filelist' (presumably as filled in 
 358         by 'add_defaults()' and 'read_template()') to the manifest file 
 359         named by 'self.manifest'. 
 361         self
.execute(file_util
.write_file
, 
 362                      (self
.manifest
, self
.filelist
.files
), 
 363                      "writing manifest file '%s'" % self
.manifest
) 
 368     def read_manifest (self
): 
 369         """Read the manifest file (named by 'self.manifest') and use it to 
 370         fill in 'self.filelist', the list of files to include in the source 
 373         log
.info("reading manifest file '%s'", self
.manifest
) 
 374         manifest 
= open(self
.manifest
) 
 376             line 
= manifest
.readline() 
 377             if line 
== '':              # end of file 
 381             self
.filelist
.append(line
) 
 386     def make_release_tree (self
, base_dir
, files
): 
 387         """Create the directory tree that will become the source 
 388         distribution archive.  All directories implied by the filenames in 
 389         'files' are created under 'base_dir', and then we hard link or copy 
 390         (if hard linking is unavailable) those files into place. 
 391         Essentially, this duplicates the developer's source tree, but in a 
 392         directory named after the distribution, containing only the files 
 395         # Create all the directories under 'base_dir' necessary to 
 396         # put 'files' there; the 'mkpath()' is just so we don't die 
 397         # if the manifest happens to be empty. 
 398         self
.mkpath(base_dir
) 
 399         dir_util
.create_tree(base_dir
, files
, dry_run
=self
.dry_run
) 
 401         # And walk over the list of files, either making a hard link (if 
 402         # os.link exists) to each one that doesn't already exist in its 
 403         # corresponding location under 'base_dir', or copying each file 
 404         # that's out-of-date in 'base_dir'.  (Usually, all files will be 
 405         # out-of-date, because by default we blow away 'base_dir' when 
 406         # we're done making the distribution archives.) 
 408         if hasattr(os
, 'link'):        # can make hard links on this system 
 410             msg 
= "making hard links in %s..." % base_dir
 
 411         else:                           # nope, have to copy 
 413             msg 
= "copying files to %s..." % base_dir
 
 416             log
.warn("no files to distribute -- empty manifest?") 
 420             if not os
.path
.isfile(file): 
 421                 log
.warn("'%s' not a regular file -- skipping" % file) 
 423                 dest 
= os
.path
.join(base_dir
, file) 
 424                 self
.copy_file(file, dest
, link
=link
) 
 426         self
.distribution
.metadata
.write_pkg_info(base_dir
) 
 428     # make_release_tree () 
 430     def make_distribution (self
): 
 431         """Create the source distribution(s).  First, we create the release 
 432         tree with 'make_release_tree()'; then, we create all required 
 433         archive files (according to 'self.formats') from the release tree. 
 434         Finally, we clean up by blowing away the release tree (unless 
 435         'self.keep_temp' is true).  The list of archive files created is 
 436         stored so it can be retrieved later by 'get_archive_files()'. 
 438         # Don't warn about missing meta-data here -- should be (and is!) 
 440         base_dir 
= self
.distribution
.get_fullname() 
 441         base_name 
= os
.path
.join(self
.dist_dir
, base_dir
) 
 443         self
.make_release_tree(base_dir
, self
.filelist
.files
) 
 444         archive_files 
= []              # remember names of files we create 
 445         for fmt 
in self
.formats
: 
 446             file = self
.make_archive(base_name
, fmt
, base_dir
=base_dir
) 
 447             archive_files
.append(file) 
 449         self
.archive_files 
= archive_files
 
 451         if not self
.keep_temp
: 
 452             dir_util
.remove_tree(base_dir
, dry_run
=self
.dry_run
) 
 454     def get_archive_files (self
): 
 455         """Return the list of archive files created when the command 
 456         was run, or None if the command hasn't run yet. 
 458         return self
.archive_files